1. 程式人生 > 其它 >React訓練營:Advanced React Hooks:useContext與useReducer

React訓練營:Advanced React Hooks:useContext與useReducer

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>
  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 元件中

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元件,在函式的引數中使用變數{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;

資料流向