入门 React Hooks 实战解析

最近在学习React,并使用 React + TypeScript 实现了一个记账应用。在本文中会总结一些 React Hooks 入门的技巧。

useState

useState 可以返回两个数据,第一个数据为初始变量,第二个数据为修改变量的方法。然后再传入一个初始值,即可完成一个 useState

比如我定义一个变量 tags,同时也需要定义一个 setTags ,方便后续对 tags 进行修改。这里的初始值是 [],一个空数组。useState 结合TS语法,需要在后面加上 <> 声明数据类型,即以下代码中的 { id: number, name: string }[]

const [tags, setTags] = useState<{ id: number, name: string }[]>([]);

//把 tags 和 setTags 暴露出去
return {tags, setTags};
复制代码

我们还可以使用 return 析构语法把 tagssetTags 暴露到外部,方便其他组件使用。项目中,需要写一个根据标签ID来确定标签的功能,就使用到了 useState 中的 tags

const findTag = (id: number) => tags.filter(tag => tag.id === id)[0];
复制代码

在制作“添加标签”功能时,使用到了 setTags 来更改 tags 的值:

    const addTag = () => {
        const tagName = window.prompt('请输入标签名');
        if (tagName !== null && tagName !== '') {
            setTags([...tags, {id: createId(), name: tagName}]);
        }
    };
复制代码

useState 中的两个返回值,也可以结合到 useEffect 中使用:

    useEffect(() => {
        let localTags = JSON.parse(window.localStorage.getItem('tags') || '[]');
        if (localTags.length === 0) {
            localTags = [
                {id: createId(), name: '衣服'},
                {id: createId(), name: '食物'},
                {id: createId(), name: '住房'},
                {id: createId(), name: '交通'}
            ];
        }
        setTags(localTags)
    }, []);
复制代码

在这个 useEffect 中,依赖值留空,可以实现在进入页面后马上渲染出数据。以上代码首先在 LocalStorage 中对标签数据进行读取,判断标签数据是否存在,如存在则在渲染UI后使用 setTags 写入数据。

useReducer

useReducer 可以理解成 useState 的高级版。

使用步骤主要为以下4步:

第一步:创建一个初始值 initialState

const initial = {
  n: 0
};
复制代码

第二步:创建对数据的所有操作,以下代码可以对数字实现 +1*2 功能:

const reducer = (state, action) => {
  if (action.type === "add") {
    return { n: state.n + action.number };
  } else if (action.type === "multi") {
    return { n: state.n * 2 };
  } else {
    throw new Error("unknown type");
  }
};
复制代码

第三步:将创建的 reducer 传给 useReducer 得到读写API,useReducer 接受两个参数,一个是 reducer,一个是 initial。返回两个参数,一个是 state 保存值,另一个是 dispatch。以下代码中 staten 就是上面 initialn

const [state, dispatch] = useReducer(reducer, initial);
const { n } = state;
复制代码

使用 dispatch 来调用之前写好的 add,数字即可+1,跟 useState 中的 setX 一样的效果。此时的 onClick 方法非常简单,对数据的操作都被集成到 reducer 中,onClick 只触发 dispatch,然后调用相应的 reducer 即可。

const onClick = () => {
    dispatch({ type: "add", number: 1 });
};
const onClick2 = () => {
    dispatch({ type: "multi", number: 2 });
};
复制代码

useEffect

在 React 的官方文档中,useEffect 可以理解成 componentDidMountcomponentDidUpdatecomponentWiilUnmount 的结合体。useEffect 接收一个函数,这个函数会在组件渲染之后才执行,返回的方式有两种。要么返回一个能清除副作用的函数,要么不返回任何内容。

一般的用法如下:

useEffect(() => {
	// 函数
}, [//更新依赖]);
复制代码

useEffect 接受两个参数。第一个是函数,放入异步操作的代码。第二个参数是依赖项数组,只要数组有变化,useEffect 就会执行。

 useEffect(() => {
        if (count.current > 1) {
            fn();
        }
    }, [fn, dependency]);
复制代码

上面代码中,只要 fndependency 发生变化,useEffect 就会执行。组件在第一次渲染时,useEffect 也会执行,如果渲染后依赖项发生变化,就会执行两次。

useContext

如果需要组件之间共享状态,可以使用 useContext。一般用于同级之间的组件通信。

使用 useContext 只需3步:

首先使用 React.createContext() 创建一个 context

const Context1 = React.createContext(null)
复制代码

使用 <Context1.Provider> 圈定作用域:

function App() {
  const [n, setN] = useState(0)
  return (
    <Context1.Provider value={{n,setN}}>
      <div className="App">
        <Dad/>
      </div>
    </Context1.Provider>
  );
}
复制代码

作用域内使用 useContext(Context1) 来使用上下文:

function Dad(){
  return(
    <div>
      我是爸爸
      <Child/>
    </div>
  )
}

function Child() {
  const { n, setN } = useContext(C);
  const onClick=()=>{
    setN(i=>i+1)
  }
  return(
    <div>我是儿子 我得到的n: {n}
      <button onClick={onClick}>+1</button>
    </div>
  )
}

复制代码

封装自定义 hook

记账软件需要对用户输入的标签进行增、删、改、查等操作,可以把这些操作都封装到一个 useTags 组件中,方便共享。

const useTags = () => {
    const [tags, setTags] = useState<{ id: number, name: string }[]>([]);
    const findTag = (id: number) => tags.filter(tag => tag.id === id)[0];
    const updateTag = (id: number, obj: { name: string }) => {
        setTags(tags.map(tag => tag.id === id ? {id, name: obj.name} : tag));

    };
    const deleteTag = (id: number) => {
        setTags(tags.filter(tag => tag.id !== id));
    };
    const addTag = () => {
        const tagName = window.prompt('请输入标签名');
        if (tagName !== null && tagName !== '') {
            setTags([...tags, {id: createId(), name: tagName}]);
        }
    };
    return {tags, setTags, findTag, updateTag, deleteTag, addTag};
};

export {useTags};
复制代码

其他组件就可以使用 useTags 中的一些方法:

const TagsSection: React.FC<Props> = (props) => {
  // 从useTags中提取出tag和addtag
    const {tags, addTag} = useTags();
    const selectedTagIds = props.value;
  	......
    return (
        <Wrapper>
            <button onClick={addTag}>新增标签</button>
        </Wrapper>
    );
};
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享