Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React避坑指南 #53

Closed
FrankKai opened this issue May 4, 2018 · 3 comments
Closed

React避坑指南 #53

FrankKai opened this issue May 4, 2018 · 3 comments

Comments

@FrankKai
Copy link
Owner

FrankKai commented May 4, 2018

  • useRef为什么可以保证事件处理器中的对象不为null?
  • React中的事件绑定onClick={handleClick}onClick={handleClick('pop')}区别是什么?
  • React除了可以通过props传递数据以外,如何通过context方式传递数据?
@FrankKai FrankKai changed the title react踩坑记录 React踩坑记录 May 4, 2018
Repository owner locked and limited conversation to collaborators May 16, 2018
@FrankKai
Copy link
Owner Author

useRef为什么可以保证事件处理器中的对象不为null?

通常来说,useRef用于引用组件的Dom节点。Vue中的ref则是引用一个vue组件。与Vue不同,react中的ref不仅仅是引用Dom节点,还可以生成一个内存不变的对象引用。

使用useState导致的空指针示例

const [foo, setFoo] = useState(null);

const handler = () => {
    setFoo("hello")
}

useEffect(() => {
    return () => {
      // 无论怎样foo都是null,给useEffect的deps加入foo也不行
      if (foo === "hello") {
          // do something...
      }
    }
}, [])

使用useRef的正确示例

const foo = useRef(null)

const handler = () => {
    foo.current = "hello"
}

useEffect(() => {

    return () => {
      // foo.current为hello
      if (foo.current === "hello") {
          // do something...
      }
    }
}, [])

useRef解决空指针问题的原因是什么?

  • 组件生命周期期间,useRef指向的对象都是一直存在的
  • 每次渲染时,useRef都指向同一个引用的对象

总结起来就是:useRef生成的对象,在组件生命周期期间内存地址都是不变的。

const refContainer = useRef(initialValue);

useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.

This works because useRef() creates a plain JavaScript object. The only difference between useRef() and creating a {current: ...} object yourself is that useRef will give you the same ref object on every render.

@FrankKai
Copy link
Owner Author

FrankKai commented Mar 29, 2021

React中的事件绑定onClick={handleOnClick}onClick={()=>handleOnClick('pop')}区别是什么?

  • 不需要传递数据:onClick={handleOnClick}
  • 需要传递数据:onClick={()=>handleOnClick('pop')}
  • 错误写法:onClick={handleOnClick('pop')}

印象很深刻的踩坑:假设将注释代码放出来,则会提醒Cannot read property 'mutateArray' of null

import React, { useEffect } from 'react';
import VisualArray from "visual-array";

function Demo() {
    const canvasConfig = {
        array: [2, 1, 9, 3, 1, 0],
        cw: 60,
        ch: 60,
        bottomIndex: null,
        topText: null,
        customStyle: null,
        _canvas: null,
    };
    useEffect(() => {
        const visualArray = new VisualArray({
            containerId: "canvas",
            array: canvasConfig.array,
            cw: canvasConfig.cw,
            ch: canvasConfig.ch,
        });
        canvasConfig._canvas = visualArray;
    }, [])
    const handleOnClick = (type: string) => {
        if (type === 'unshift' || type === 'push') {
            if (canvasConfig._canvas) {
                canvasConfig._canvas.mutateArray(type, Math.floor(10 * Math.random()))
            }
            return;
        }
        canvasConfig._canvas.mutateArray(type)
    }

    return (
        <div className="demo">
            <div id="canvas"></div>
            <button onClick={() => { handleOnClick('unshift') }}>unshift</button>
            <button onClick={() => { handleOnClick('push') }}>push</button>
            <button onClick={() => { handleOnClick('shift') }}>shift</button>
            <button onClick={() => { handleOnClick('pop') }}>pop</button>
            {/* <button onClick={handleOnClick('pop')}>pop</button> */}
        </div>
    );
}

export default Demo;

@FrankKai
Copy link
Owner Author

React除了可以通过props传递数据以外,如何通过context方式传递数据?

假设组件层级较深,props需要一级一级往下传,可以说是props hell问题。
context方式封装的组件,为需要接受数据的组件,提供了一种跨组件层级传递,按需引入上级props的方式。

组件定义context部分

import * as React from 'react'
// myContext.ts
interface IContext {
     foo: string,
     bar?: number,
     baz: string
}
const myContext = React.createContext<IContext>({
     foo: "a",
     baz: "b"
})


interface IProps {
    data: IContext ,
}

const myProvider: React.FC<IProps> = (props) => {
     const {data, children} = props
     return <myContext.Provider value={data}>{children}</myContext.Provider>
}

export default myProvider;

export function useMyContext() {
  return useContext(myContext)
}

使用组件和context部分

<!-- 组件包裹 -->
import myProvider from './myContext.ts'

<myProvider data={{foo: "foo", baz: "baz"}}>
    <div className="root">
        <div className="parent">
            <Component1 />
            <Component2 />
        </div>
     </div>
</myProvider>
// Component1
import  {useMyContext} from './myContext.ts'
const {foo, baz} = useMyContext()

const Compoonent1 = () => {
    return (<div>{foo}{baz}</div>)
}
export Component1

@FrankKai FrankKai changed the title React踩坑记录 React避坑指南 Mar 29, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

1 participant