React Hooks + Context для создания простого сокращения

React.js
React Hooks + Context для создания простого сокращения

HookдаReact 16.8новая функция, позволяющая писать безclassиспользовать в случае компонентов классаstateи другиеReactхарактеристики; иContextдаReact16.3представлена ​​новая версияContext API, в прошломReactВ версии естьContext API, это закулисная экспериментальная функция, и ее официально предлагается избегать,ReduxПринцип состоит в том, чтобы строить на старомContext API. новый сейчасContext ApIПредоставляет метод для передачи данных между деревьями компонентов без ручного добавления свойств для каждого уровня компонентов, открывая новый способ передачи данных.

Введение в контекст

Для того, чтобы решить проблему многоуровневой вложенности между компонентами на разных уровняхpropsПередача данных, этот вид передачи данных очень сложен, и его нелегко поддерживать позже, чтобы избежатьdrilingпередача данных, можно использоватьreduxпередача данных. в новой версииReact 16.8.6серединаContextПринесите нам новый способ общения.

Context APIкомпонент

  • React.createContextфункция: создатьcontextконтексте параметр является значением по умолчанию (необходимо передатьstateданные),stateвозможноObject、ArrayИли существенно типы данных.

  • Provider:Зависит отReact.createContextСоздайте свойство, которое возвращает объект. существуетRedux vs. The React Context APIКитайская метафора похожа на построение дерева компонентов в电子总线Сравните изображение.

  • Consumer:Зависит отReact.createContextСоздайте свойство, которое возвращает объект. доступ к метафоре电子总线получить данные.

Context vs redux

Contextизcontext.Provider/Context.Consumerа такжеreduxизprovider/connectочень похожий.ContextИспользуя шаблон производитель-потребитель, мы можем использовать функции более высокого порядка (Hoc) имитирует реализациюredux.

reduxчерезdispatchОдинactionмодифицироватьstoreданные; вReact 16.8.6версияReact hooksкоторый предоставилuseredcuersа такжеuseContextоблегчи нам проходContext+hooksформу для созданияredux

ContextПростой пример

ContextОн предназначен для обмена данными, которые являются «глобальными» для дерева компонентов, например, текущий аутентифицированный пользователь, тема или предпочитаемый язык.

  • Class.contextType

Прикреплено кclassВверхcontextTypeИмущество будет передано другомуReact.createContext()созданныйContextобъект.这能让你使用this.contextпотреблять в последнее времяContextзначение выше. Вы можете получить к нему доступ в любом жизненном цикле, включаяrenderв функции.

  • Context.Consumer

Позволяет подписаться на функциональные компонентыcontext. Это требует практики функционирования в детстве. Эта функция получает текущийcontextзначение, возвращаетReactузел. передается в функциюvalueЗначение эквивалентно переходу вверх по дереву компонентов от этогоcontextнедавнийProviderкоторый предоставилvalueстоимость. Если нет соответствующегоProvider,valueпараметр эквивалентен переходу кcreateContext()изdefaultValue.

// Context 可以让我们无须明确地传遍每一个组件,就能将值深入传递进组件树。
// 为当前的 theme 创建一个 context(“light”为默认值)。
const ThemeContext = React.createContext('light');

class App extends React.Component {
  render() {
    // 使用一个 Provider 来将当前的 theme 传递给以下的组件树。
    // 无论多深,任何组件都能读取这个值。
    // 在这个例子中,我们将 “dark” 作为当前的值传递下去。
    return (
      <ThemeContext.Provider value="dark">
        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}

// 中间的组件再也不必指明往下传递 theme 了。
function Toolbar(props) {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

class ThemedButton extends React.Component {
  // 指定 contextType 读取当前的 theme context。
  // React 会往上找到最近的 theme Provider,然后使用它的值。
  // 在这个例子中,当前的 theme 值为 “dark”。
  static contextType = ThemeContext;
  render() {
    return <Button theme={this.context} />;
  }
}
// 也可以按照这种形式获取
function ThemedButton(){
    return (
      <ThemeContext.Counsumer>
        {theme =>(
         <Button theme={theme} />
         )
  		}
       </ThemeContext.Counsumer>
      );
}

contextПодробное использование см.Контекстная документация

React Hooks

React HooksдаReact 16.8.6Версия добавляет выборку в каждом жизненном цикле функциональных компонентов.stateа такжеpropsканал. Позволяет использовать состояние и другие функции React без написания классов. больше не нужно писатьclassКомпоненты, все ваши компоненты будутFunction. Если вы хотите узнать больше оReact hooksИнформация может относиться кСправочник API хуков.

Базовый API хука

  • useState: получить компонентstateДанные о состоянии, первый параметр - это сохраненные данные, второй параметр - это метод рабочих данных, аналогичныйsetState. доступныйES6Назначение деструктуризации массива для получения.
  • useEffect: сетевой запрос, подписка на модуль,DOMоперации являются побочными эффектами.useEffectпредназначен для борьбы с побочными эффектами. существуетclassВ компонентах классаcomponentDidMountа такжеcomponentDidUpdateФункции жизненного цикла используются для обработки побочных эффектов.
  • useContext:useContextЛегко подписатьсяcontextизменяет и повторно отображает компонент, когда это необходимо. Например, в функциональном компоненте выше,Consumerполученный в видеContextданные, сuseContextМожно переписать следующим образом:
function ThemedButton(){
    const value = useContext(ThemeContxet);
    return (
         <Button theme={value} />
      );
}

useReducers API

если ты привыкнешь к этомуreduxпройти черезreducerИзменятьstateилиpropsформу, должно быть легче начатьuseReducers,useReducersа такжеuseContextнаходится в центре внимания этой статьиAPI.

  • useReducers:useReducersМожно передать три параметра, первый пользовательскийreducer, второй параметр — это значение по умолчанию для инициализации, а третий параметр — это функция, которая принимает второй параметр для вычисления, чтобы получить значение по умолчанию (необязательно).
const [state,dispatch] = useReducer(reducer,initialValue)

НижеuseReducersОфициальный пример:

const initialState = {count: 0};

function reducer(state, action) {
  switch (action.type) {
    case 'reset':
      return initialState;
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    default:
      // A reducer must always return a valid state.
      // Alternatively you can throw an error if an invalid action is dispatched.
      return state;
  }
}

function Counter({initialCount}) {
  const [state, dispatch] = useReducer(reducer, {count: initialCount});
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({type: 'reset'})}>
        Reset
      </button>
      <button onClick={() => dispatch({type: 'increment'})}>+</button>
      <button onClick={() => dispatch({type: 'decrement'})}>-</button>
    </>
  );
}

Простой Редукс

reduxимеютProviderкомпоненты, черезstoreпередать значение. Здесь мы используемContextРеализация моделированияProviderа такжеstoreПередайте значение, полный код может относиться кsimple-redux.

упаковкаProviderкомпоненты

в кодеstoreContextдаReact.createContext()Объект Context, созданный функцией.this.props.storeмоделируетсяstoreоперации передачи по значению.

import React,{Component} from 'react';
import {storeContext} from './store';
export default class Provider extends Component{
    render(){
        return (
            <storeContext.Provider value={this.props.store}>
                {this.props.children}
            </storeContext.Provider>
        )
    }
}

управление данными магазина

storeдокументы, в том числеreducer,ContextсозданиеinitialStateа такжеreducersОпределение.

import React from 'react';
export const storeContext = React.createContext();
export const initialState = {
    user:'kiwis',
    age:23
}
export const reducer = (state, action)=>{
    switch (action.type) {
      case 'CHANGENAME':
        return {user:'harhao',age:24}
      default:
        return initialState;
    }
}

Запись App.js

в корневом компонентеApp.jsв использованииReact hooksд изuseReducerФункция ловушки, возврат измененийstateизdispatchфункция. тогда поставьstoreданные иdispatchперешел в пакетProviderв компоненте.

import React,{useReducer} from 'react';
import Provider from './views/Provider';
import Child from './views/child';
import {initialState as store,reducer} from './views/store';
import './App.css';

function App() {
  const [state,dispatch] = useReducer(reducer,store);
  return (
    <div className="App">
      <Provider store={{state,dispatch}}>
        <Child/>
      </Provider>
    </div>
  );
}
export default App;

Пользовательский хук useConnect

существуетuseConextОберните слой функций для лучшего моделированияconnectграмматика. обычай здесьReact hooksМетоды. определить обычайhookфункцияuseConnect,Следующим образом:

import {useConext} from 'react';
export default function useConnect(props){
    return useContext(props);
}

Дочерний компонент

существуетApp.jsподкомпонентChildв, вreduxпрошедшийconnectФункции высшего порядка для передачи данных. Здесь вы можете использовать пользовательскиеReact hooksфункцияuseConnectПолучатьstateа такжеdispatch.

import React,{useContext} from 'react';
import useConnect from './connect';
import {storeContext} from './store';
import DeepChild from './deepChild';
function Child() {
    const {state,dispatch}= useConnect(storeContext);
    return (
        <div className="child">
            <p>姓名:{state.user}</p>
            <p>年龄:{state.age}</p>
            <button onClick={()=>dispatch({type:'CHANGENAME'})}>changeName</button>
            <p>deep child:</p>
            <DeepChild/>
        </div>

    );
}

export default Child;

DeepChild (внучатый компонент)

существуетChildВ подкомпонентах импортироватьDeepChildкомпоненты. пройти черезuseContextПолучить топ ближайшийstateданные.

import React,{useContext} from 'react';
import {storeContext} from './store';
import useConnect from './connect';
export default function DeepChild(){
    const {state} = useConnect(storeContext);
    return (
        <div>
            {state.user}
        </div>
    )
}

текущий результат

childПодкомпоненты иDeepChildКомпонент Sun пройденuseConnectПолучите данные верхнего уровня, окончательный результат работы выглядит следующим образом, вы можете пройтиGitpodНаблюдайте за исполнением и структурой кода в режиме реального времени

Open in Gitpod

demo

Если вам понравилось, можете поставить лайк~ или звездочку~
гит-адрес:GitHub.com/ha молоко хорошее/простое…

Справочная статья
Реагировать на китайскую документацию
Полное руководство по React Redux 2019
[Перевод] Redux и контекстный API React
Анализ хуков React (Часть 1): Основы
Анализ хуков React (часть 2): продвинутый уровень