react基础(二)完 | 字节青训营笔记

72 阅读3分钟

三、业务场景与案例

(一)父子组件通信案例

在React中,父子组件之间可以通过多种方式进行通信。父组件可以通过props向子组件传递数据,子组件可以通过回调函数或事件冒泡向父组件传递信息。

下面是一个简单的例子,展示了如何使用props和回调函数实现父子组件之间的通信:

class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { message: "" };
  }

  handleMessage = (message) => {
    this.setState({ message });
  };

  render() {
    return (
      <div>
        <Child onMessage={this.handleMessage} />
        <p>Message from child: {this.state.message}</p>
      </div>
    );
  }
}

const Child = ({ onMessage }) => {
  const handleClick = () => {
    onMessage("Hello from child!");
  };

  return <button onClick={handleClick}>Send Message</button>;
};
复制代码

在这个例子中,Parent 组件通过 propsChild 组件传递了一个回调函数 handleMessage。当 Child 组件中的按钮被点击时,它会调用这个回调函数并传递一个消息给 Parent 组件。然后,Parent 组件会更新它的状态并显示来自 Child 组件的消息。

(二)组件间共享信息_Reducer & Context

在React中,可以使用Reducer和Context来拓展应用。Reducer可以整合组件的状态更新逻辑,而Context可以将信息深入传递给其他组件。你可以组合使用它们来共同管理一个复杂页面的状态。

这是一个使用Context和Reducer的例子,演示了如何在React中使用它们来共享状态。在这个例子中,我们创建了一个ProfileContext,并使用useReducer来管理状态。还定义了一个reloadProfile函数来异步获取数据,并在组件中使用useEffect来调用它。最后,将状态和dispatch函数传递给ProfileContext.Provider,以便在组件树中的其他组件中访问它们。

import React, { useCallback } from 'react'

const ProfileContext = React.createContext()

const initialState = {
  data: false
}

let reducer = (state, action) => {
  switch (action.type) {
    case 'unload':
      return initialState
    case 'profileReady':
      return { data: action.payload }
  }
}

const reloadProfile = async () => {
  try {
    let profileData = await fetch('/profile')
    profileData = await profileData.json()
    return profileData
  } catch (error) {
    console.log(error)
  }
}

function ProfileContextProvider(props) {
  let [profile, profileR] = React.useReducer(reducer, initialState)

  const customDispatch = useCallback(async (action) => {
    switch (action.type) {
      case 'reload': {
        const profileData = await reloadProfile()
        profileR({ type: 'profileReady', payload: profileData })
        break
      }
      default:
        // Not a special case
        profileR(action)
    }
  }, [])

  return (
    <ProfileContext.Provider value={{ profile, customDispatch }}>
      {props.children}
    </ProfileContext.Provider>
  )
}

export { ProfileContext, ProfileContextProvider }
复制代码

image.png

(三)组件间共享信息_redux

另一种在React中实现组件之间信息共享的方法是使用Redux。Redux是一个独立的状态管理库,它可以与React一起使用。在Redux中,我们可以定义一个全局的store来存储应用程序的状态。然后,定义action来描述状态的变化,并使用reducer函数来处理这些action并更新状态。

下面是一个简单的例子,它演示了如何在React中使用Redux来共享状态:

import { createStore } from 'redux'

// 1. 定义初始化的state
const initState = {
  num: 0
}

// 2. 定义action
function add() {
  return { type: 'INCREMENT' }
}

function dec() {
  return { type: 'DECREMENT' }
}

// 3. 编写reducer函数
function reducer(state = initState, action) {
  switch (action.type) {
    case 'INCREMENT':
      return { num: state.num + 1 }
    case 'DECREMENT':
      return { num: state.num - 1 }
    default:
      return state
  }
}

// 4. 创建store
const store = createStore(reducer)

// 5. 使用dispatch触发action
store.dispatch(add())
store.dispatch(add())
store.dispatch(dec())
复制代码

(四)你不知道的冒泡_Portal

在React中,我们可以使用Portal来将子节点渲染到父组件DOM层次结构之外的DOM节点。这可以通过调用ReactDOM.createPortal(child, container)来实现。其中,child是要渲染的React元素,而container是要将子节点插入到的DOM元素。

export default function App() {
  const [isShow, setIsShow] = useState(false);
  function click(e) {
    console.info("e", e);
    setIsShow(!isShow);
  }
  return (
    <div
      style={{ backgroundColor: "#a00", width: `200px`, height: `100px` }}
      onClick={click}
    >
      {isShow && (
        <Modal>
          <span>zhangsan</span>
        </Modal>
      )}
    </div>
  );
}
复制代码

虽然Portal可以将子节点渲染到父组件DOM层次结构之外的DOM节点,但是它仍然遵循React的事件冒泡机制。也就是说,如果你在Portal中触发了一个事件,它会沿着React组件树向上冒泡,而不是沿着实际渲染的DOM元素结构。