Saber2pr's Blog

组件通信

子组件调用父组件

  1. 使用 props 数据流(单向向下)
const Parent = () => {
  const [state, setState] = useState(0)
  return <Child update={setState} />
}

const Child = ({ update }) => (
  <button onClick={() => update(233)}>update</button>
)
  1. 使用 Context
const Context = React.createContext()

const Parent = () => {
  const [state, setState] = useState(0)
  return (
    <Context.Provider value={{ update: setState }}>
      <Child />
    </Context.Provider>
  )
}

const Child = () => (
  <Context.Consumer>
    {({ update }) => <button onClick={() => update(233)}>update</button>}
  </Context.Consumer>
)

或者

const Context = React.createContext()

const Parent = () => {
  const [state, setState] = useState(0)
  const context = useContext(Context)
  context.update = setState
  return <Child />
}

const Child = () => {
  const { update } = useContext(Context)
  return <button onClick={() => update(233)}>update</button>
}

父组件调用子组件

使用 ref

const Parent = () => {
  const ref = useRef()

  useEffect(() => {
    ref.current.update(233)
  })

  return <Child ref={ref} />
}

const Child = React.forward((props, ref) => {
  const [state, setState] = useState(0)

  useImperativeHandle(ref, () => ({
    update: setState
  }))

  return <p>{state}</p>
})

兄弟组件通信

由于 React 单向数据流的特点,所以数据只能从上向下传递。所以组件需要调用父组件 setState,来发布新的数据流向兄弟组件。

const Parent = () => {
  const [state, setState] = useState(0)
  return (
    <>
      <Child1 update={setState} />
      <Child2 state={state} />
    </>
  )
}

const Child1 = ({ update }) => (
  <button onClick={() => update(233)}>update child2</button>
)

const Child2 = ({ state }) => <p>{state}</p>

redux

redux 与 react 没有必然关系。redux 是一个观察者模式 + compose 的实现。上述例子可以看出数据会单向传递到视图上,而数据传递需要事件来触发,即视图是数据的订阅者,数据变化,视图也相应作出变化。所以 redux 与 react 可以很好的配合。但 redux 的事件触发相对频繁,如果不做优化,react 会进行大量无用的更新(rerender)逻辑,所以在 react-redux 库中,将订阅数据的订阅器进行了优化,减少了很多 rerender。

react-redux 所做的优化

至于需不需要引入 redux,其实仔细想,使用 context、ref 足够了。