【React】facebook最新状态管理库Recoil

13 篇文章 0 订阅

前言

  • 我感觉这个recoil还是挺有前途的,因为redux实际有些不太好的地方,我草稿箱里还有篇讨论redux僵尸children与陈旧props的文章没整理出来。
  • 一个库出来我们先学会去使用他,再去搞原理什么的。这玩意有官方光环,必然不是那种随便写写就不维护了或者只是个玩具的东西。
  • 它这个库应该是解决redux祖先传来导致更新问题,同时也解决僵尸children与陈旧props的问题,也就是异步刷新取值。本来我也想自己写个类似的东西,既然有官方的就懒得写了。
  • https://recoiljs.org/docs/introduction/motivation 在动机这里,recoil官方也指出了这个库解决的问题,这个库也是flow编写的,注释写的倒是挺多,可以学学大神咋写的。

官网

安装

  • 直接开个新项目 然后安装recoil
npm install recoil

快速上手

  • 按说明给的demo写出下面这套:
import React from "react";
import {
	RecoilRoot,
	atom,
	selector,
	useRecoilState,
	useRecoilValue,
} from "recoil";

const textState = atom({
	key: "textState", // unique ID (with respect to other atoms/selectors)
	default: "", // default value (aka initial value)
});

const charCountState = selector({
	key: "charCountState", // unique ID (with respect to other atoms/selectors)
	get: ({ get }) => {
		const text = get(textState);

		return text.length;
	},
});


function CharacterCounter() {
	return (
		<div>
			<TextInput />
			<CharacterCount />
		</div>
	);
}

function CharacterCount() {
  //此处模拟children2
	const count = useRecoilValue(charCountState);
	return <>Character Count: {count}</>;
}


function TextInput() {
  //此处模拟children1
	const [text, setText] = useRecoilState(textState);
	const onChange = (event: React.ChangeEvent<HTMLInputElement>) => {
		setText(event.target.value);
	};

	return (
		<div>
			<input type="text" value={text} onChange={onChange} />
			<br />
			Echo: {text}
		</div>
	);
}

function App() {
	return (
		<RecoilRoot>
			<CharacterCounter />
		</RecoilRoot>
	);
}

export default App;

  • 我们从useRecoilValue 中通过get取出了文本字符串,返回的对象即为取出的对象。
  • 而状态定义使用useRecoilState而非useState或者直接写入store。
  • 这里可以看见定义值和取值都要整个key做唯一Id,官网介绍说一些高级的功能需要使用这个。
  • 前面那个没有在同一个组件取值,同一组件取值设值是没有问题的:
const fontSizeState = atom({
	key: "fontSizeState",
	default: 14,
});
const fontSizeLabelState = selector({
	key: "fontSizeLabelState",
	get: ({ get }) => {
		const fontSize = get(fontSizeState);
		const unit = "px";

		return `${fontSize}${unit}`;
	},
});
function FontButton() {
	const fontSizeLabel = useRecoilValue(fontSizeLabelState);
	const [fontSize, setFontSize] = useRecoilState(fontSizeState);

	return (
		<>
			<div>Current font size: ${fontSizeLabel}</div>

			<button
				onClick={() => setFontSize(fontSize + 1)}
				style={{ fontSize }}
			>
				Click to Enlarge
			</button>
		</>
	);
}
  • hooks的位置对掉也不会影响输出,它可以确保拿到的始终是最新值,并且组件只刷新了一次。

API

<RecoilRoot …props />

  • 这个就是上下文,应该不用介绍都懂。
  • 它有个类似redux的可选初始值,用于设定初始值,不像redux的store要先把reducer甩进去,这个不传可以异步进行设定,可以说相当强大。
initializeState?: (MutableSnapshot => void)

State

  • state方面有很多api,功能都是比较类似的
atom(options)
function atom<T>({
  key: string,
  default: T | Promise<T> | RecoilValue<T>,

  effects_UNSTABLE?: $ReadOnlyArray<AtomEffect<T>>,

  dangerouslyAllowMutability?: boolean,
}): RecoilState<T>
  • recoilvalue是RecoilValue<T> = RecoilValueReadOnly<T> | RecoilState<T>; 而这2实际是:
// recoilValue.d.ts
declare class AbstractRecoilValue<T> {
  __tag: [T];
  __cTag: (t: T) => void; // for contravariance

  key: NodeKey;
  constructor(newKey: NodeKey);
}

declare class AbstractRecoilValueReadonly<T> {
  __tag: [T];

  key: NodeKey;
  constructor(newKey: NodeKey);
}
  • effects_UNSTABLE是一个实验性功能,感觉这个功能需要解决最大问题就是无限循环问题。由于是个实验性功能,暂不介绍也不使用它。
  • dangerouslyAllowMutability 这个东西我也是花了点时间搞明白了。里面涉及到一点它们的处理,他们对对象做了深冻结,所以如果你定义的是对象,那么你无法直接在对象上进行修改,因为react是可不可变的值,你如果做了修改,那么就不符合这个原则。但有时我可能要这么做:

const userState = atom<{ xx: string } | null>({
	key: "userState",
	default: null,
	dangerouslyAllowMutability: false,
});

function UserComp() {
	const [user, setUser] = useRecoilState(userState);
	return (
		<>
			<div> : {user && user.xx}</div>

			<button
				onClick={() => {
					setTimeout(() => {
						setUser((pre) => {
							console.log(pre);
							if (pre) {
								pre.xx = pre.xx + "1";
								return { ...pre };
							} else {
								return { xx: "111" };
							}
						});
					}, 1000);
				}}
			>
				Click to Enlarge
			</button>
		</>
	);
}

const getUser = selector({
	key: "getUser", // unique ID (with respect to other atoms/selectors)
	get: ({ get }) => {
		const user = get(userState);
		//这里类似于useselector
		return user?.xx;
	},
});

function Parent() {
	return (
		<div>
			<UserComp></UserComp>
			<Children></Children>
		</div>
	);
}

function Children() {
	const user = useRecoilValue(getUser);
	return <div>{user}</div>;
}
  • 你会看见控制台打印:
Cannot assign to read only property 'xx' of object '#<Object>'
  • 这个就是冻结生效,所以会有这个选项, 当写成true后,你便可以这么操作。
  • 如果你错误的返回了pre:
if (pre) {
pre.xx = pre.xx + "1";
			return pre;
		} else {
			return { xx: "111" };
		}
  • 组件将不会更新。所以这个也是有意在引导用户正确的使用react。
  • 而为啥叫atom,我感觉也是有意让用户使用更基础的变量而非对象。这样在性能上比使用对象会有更大提升。这样粒度更细就不会有啥无用更新。
  • 所以,对于组件内使用,atom定义完后使用自定义hook,也分为了好几种:
    useRecoilState():打算同时读取和写入atom时,请使用此钩子。这个钩子使组件订阅atom。
    useRecoilValue():仅打算读取atom时,请使用此钩子。这个钩子将组件订阅到atom上。
    useSetRecoilState():仅打算写入atom时,请使用此钩子。
    useResetRecoilState():使用此钩子将atom重置为其默认值。
selector(options)
  • 这玩意就是固定返回一个状态,看成纯函数
function selector<T>({
  key: string,

  get: ({
    get: GetRecoilValue
  }) => T | Promise<T> | RecoilValue<T>,

  set?: (
    {
      get: GetRecoilValue,
      set: SetRecoilState,
      reset: ResetRecoilState,
    },
    newValue: T | DefaultValue,
  ) => void,

  dangerouslyAllowMutability?: boolean,
})
  • 选择器可以动态获取:
const toggleState = atom({key: 'Toggle', default: false});

const mySelector = selector({
  key: 'MySelector',
  get: ({get}) => {
    const toggle = get(toggleState);
    if (toggle) {
      return get(selectorA);
    } else {
      return get(selectorB);
    }
  },
});
  • 剩下的以后写。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

业火之理

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值