Day 22 Context

第 22 天 !

当我们资料项下传递的时候,

会发现,

component 的阶层越深,

传递资讯会越困难,

因为代表的是,需要不断做向下传递的动作,

假如阶层数太多,会导致我们中间传递过程中段的话,

很容易造成错误,

打个比方:

假如最後参数要使用在 Child3 , 起点在 App

<App>
  <Child1>
    <Child2>
      <Child3></Child3>
    </Child2>
  </Child1>
</App>

那我们就必须照这样的路径 App -> Child1 -> Child2 -> Child3

把资料送到 Child3

这样做会产生一些问题:

  • 没有用到的上层必须去特别为下层定义这个参数
  • 传送链太长,不容易维护

那在 React 里,有个可以打破这个规矩的存在,

就是 context !!

context 分为 Provider(提供者) & Consumer(消费者)

当使用 context 时,

会由 Provider 建立 value , 并广播给相同 context 的 Consumer ,

那中间不用经过 props 的传递 ,

关系就是 Provider -> Consumer

建立 context

我们要使用 React.createContext 来建立,

import React from 'react';

export const AppContext = React.createContext({
  theme: {},
  toggleTheme: () => {},
});

createContext 本身塞入欲要提供的参数格式,非此定义的,都无法做传送

那在我们要建立 Providercomponent 下引入我们定义好的 context,并把 Provider 放进去

like:

<AppContext.Provider value={this.state.contextParams}>
  <SafeAreaView style={styles.root}>
    <Header
      searchList={this.searchList}
      createToDoItem={this.createToDoItem}
      handleCompleteAll={this.handleCompleteAll}
    />
    <FlatList
      data={list.filter((item) => item.text.includes(filterKey))}
      renderItem={({ item, index, separators }) => {
        const isEven = index % 2 === 0;
        const isDone = item.status === 'done';
        return (
          <ToDoItem
            isEven={isEven}
            isDone={isDone}
            text={item.text}
            onPress={this.changeItemStatus(item.id)}
          />
        );
      }}
      keyExtractor={(item) => item.id}
    />
  </SafeAreaView>
</AppContext.Provider>

建立好的 context 会提供两个 component ,

  • Provider
  • Consumer

Provider 放在资料源头, 会提供一个 props value,

在此置入我们要提供的参数物件,

那只要 value 有变动 , 相应的 Consumer 也会产生变动,

那变动的判定方式就是用 Shallow compare (===) 去判定,

所以不能用 inline 的方式植入 value ,

否则会产生无意义的渲染,徒增消耗,

所以会放入 state 去定义,

那为什麽要放入 state ,

因为只有这样才能去触发 re-rendervalue 才能改变

this.state = {
  filterKey: '',
  inputValue: '',
  list: [],
  contextParams: {
    theme: {
      header: {
        backgroundColor: '#cfcf00',
      },
    },
    toggleTheme: this.toggleTheme,
  },
};

假如希望 context 里的值,可以在 Consumer 上做改变,

那必须提供相应的改变 function,

toggleTheme = (backgroundColor) => {
  this.setState((prevState) => ({
    contextParams: {
      theme: {
        header: {
          backgroundColor,
        },
      },
    },
    ...prevState.contextParams,
  }));
};

那在指定的 component , 放入 Consumer

export class Header extends Component {
  render() {
    return (
      <AppContext.Consumer>
        {({ theme, toggleTheme }) => {
          return (
            <View style={[styles.root, theme.header]}>
              <Text style={styles.title}>My To Do List</Text>
              <View style={styles.buttonGroup}>
                <FeatureButton
                  text={'Change Color'}
                  onPress={() => toggleTheme('#F0F')}
                />
              </View>
            </View>
          );
        }}
      </AppContext.Consumer>
    );
  }
}

Consumer 的里面放入的是 component, 不是React element

它会把 contextprops 方式传入,

我们得到 themetoggleTheme

theme.header 定义 Header component 背景颜色,

用 toggleTheme 改变

结果如下:

Result


<<:  均线的重要性-价值千金

>>:  Day22 - 针对 Metasploitable 3 进行渗透测试(3) - Msfvenom 与 multi/handler

D13 第七周 (回忆篇)

这礼拜进度缓慢了下来,还在跟第六周的切版作业奋斗。到这边才慢慢找到自己切版比较顺的流程 RWD 一开...

Day 13:RecyclerView 基本资料列表显示

本篇文章同步发表在 HKT 线上教室 部落格,线上影音教学课程已上架至 Udemy 和 Youtu...

[Day01] 前言

参赛动机 笔者正在转职前端工程师的路上,过去一直知道有铁人赛,也有参加的念头,但由於本人的惰性及害怕...

JavaScript学习日记 : Day11 - 函数绑定

当object中的function作为callback function传递给setTimeout时...

[Day05] Vue i18n - Component Interpolation

在本地化 (localize) 文字讯息时,我们可能会遇到需要特别处理 HTML tag的情况,什...