React训练营:Advanced React Hooks:useContext与useReducer

概述

本文将介绍如何在React中使用Hook获取组件的数据,更进一步使用Redux进行跨组件的数据传递。配置环境后,你将了解如何编写Context、Reducer代码。

重要

  • 本文将给出如下内容:
  • React中组件之间的数据流向
  • 跨组件数据传递 Context Reducer
  • 在一个社交App的开发中,将主文件的数据传递给子组件 App->PostList->Post
  • 数据直接从App传递到Post

前置条件

  • 构建react项目
  • react中构建组件

React Hooks

React Hooks 用于组件之间的数据传递,相当于用一个钩子把函数调用过程中的变量“钩”出来。
在React开发中,组件之间的数据传递需要学习的语法为Context和Reducer的方式进行数据传递。

useContext

useContxt顾名思义,为上下文,在计算机科学中,有Context Free Language 和 Non-Context Free Language。在React中其实就是一种上下文的数据传递形式,例如组件A->组件B的单向数据流动,那么根据常见的思路:也可以理解为生产者->消费者模式。
采用Context传递数据的案例:假设在一个社交系统中,App组件中记录了登录的用户信息,此时如果要将这个信息传递到用户消息的子组件中,并显示出来:

  1. 在App组件中定义全局的Context
export const UserContext = React.createContext();

App函数中定义状态:

const [user,setUser] = React.useState('mttt');
const [posts,setPosts] = React.useState([]);

使用UserContext,render的返回值为:

<UserContext.Provider value={user}>
    <PostList posts={posts}></PostList>
</UserContext.Provider>

由于之前定义了[user,setUser]作为状态,此时的<Provider/>中value的值为user,该组件将数据传递到子组件

  1. 在PostList组件中
import React from "react";
import Post from "./Post";
function PostList({posts}) {
    return <div>
    {posts.map((post,i)=>(<Post key={i} 
                            image={post.image} 
                            content={post.content} 
                            user={post.user}/>))}
    </div>;
}
export default PostList;

3.在Post 组件中使用父组件的Context:(注意该代码中有两种传递数据的方式)
1)Post()函数的参数,({image,content,user})
2)使用Context,在App函数中定义了UserContext.Provider,需要使用参数的Post组件上,导入并使用useContext(UserContext)。Post组件中,像钩子一样把数据从App这个组件中勾出来

import React from "react";
import {UserContext} from '../App';
function Post({image,content,user}){
    const currentUser = React.useContext(UserContext);
    const isCurrentUser = currentUser === user;
    return (
        <>
        <div>
        <p>{content}</p>
        <div style={{color:isCurrentUser&&'green'}}>{user}</div>
        </div>
        {image && (
            <img
                style={{height:100, width:200, obejct:'cover'}}
                src = {URL.createObjectURL(image)}
                alt = "Post cover"
            />)} 
        </>
    );
}
export default Post;

数据流向为:
App->PostList->Post的数据流
App组件到PostList组件,在函数的参数中使用变量{posts}进行参数传递,PostList组件到Post组件,也是使用类似的方法,就像钩子一样,把数据勾出来,但是此时通过函数参数单方向传递数据,只能一层一层传递参数,演示的例子中,使用了Context也就是最上层的App组件中定义了<UserContext.Provider value={user}>,作为数据生产者,而在最底层的Post组件中使用了const currentUser = React.useContext(UserContext);作为数据的消费者,得到了顶层组件的数据,此时的数据可以跨层流动,相比于直接通过函数参数的数据传递,Context的方式传递,自由度更大!

使用Reducer

Reducer使用纯函数的思想,参数为state和action,返回值为newState
state: state = {value: }
action:const action={type:"LOGIN_USER",payload:{ username:"xmmt"}};

const initialState = { user:""};

function userReducer(state=initialState,action){
  switch(action.type){
    case "LOGIN_USER": {
      return {
          ...state, 
          user: action.payload.username };
      }
    case "LOGOUT_USER": {
          ...state,
          user:""
      }
    default:
      return state;
  }
}
const loginAction = { type:"LOGIN_USER",payload:{username:"xmmt"}};
const logoutAction = { type:"LOGOUT_USER"}
userReducer(initialState,loginAction);
userReducer(initialState,logoutAction);

使用Reducer 对用户评论列表进行新增和删除

Reducer的定义,编写state 和 action

function postReducer(state,action){
    switch (action.type) {
        case "ADD_POST":{
            const newPost = action.payload.post;
            return { posts:[newPost,...state.posts]};
        }
        case "DELETE_POST":{
            const deletePostId = action.payload.id;
            return { posts:state.posts.filter(post=>post.id!==deletePostId)} 
        }
        default:
            return state;
    }
}
export default postReducer;

App组件

全局变量posts存储用于发送的评论(微博)之类的内容:
export const PostContext = React.createContext({
    posts:[]
});
function App(){
  ...
  const [state,dispatch] = React.useReducer(postReducer,initialPostState);

  return (
    ...
      <PostList posts={state.posts}></PostList>
    ...
  )
}

参数从App到PostList再到Post组件

import React from "react";
import {UserContext,PostContext} from '../App';
function Post({image,content,user,id}){
    const { dispatch } = React.useContext(PostContext);
    const currentUser = React.useContext(UserContext);
    const isCurrentUser = currentUser === user;
    function handleDeletePost(){
        dispatch({type:"DELETE_POST",payload:{id:id}});
    }
    return (
        <>
        <div>
        <p>{content}</p>
        <div style={{color:isCurrentUser&&'green'}}>{user}</div>
        </div>
        {image && (
            <img
                style={{height:100, width:200, obejct:'cover'}}
                src = {URL.createObjectURL(image)}
                alt = "Post cover"
            />)} 
        { isCurrentUser && <button onClick={handleDeletePost}>Delte</button>}
        </>
    );
}
export default Post;

数据流向

posted @ 2022-03-27 17:59  adminmttt  阅读(98)  评论(0编辑  收藏  举报