用Immerjs编写更好的JavaScript和ReactJS代码
#javascript #react #数据结构 #immer

什么是不变的状态?

这是一个不会随时间变化的状态。

因此,当我们创建一个不变的对象时,我们不会更改其属性,如果需要更改其属性,我们会创建其新副本,并根据需要修改属性。

在JavaScript中,我们可以同时使用可变态和不可变的状态,我们决定哪种对我们更好,我们可以使用 object.freeze.freeze()使我们的对象变得不可变。

让我们有一个例子,我们有一个称为状态的对象...

const state = {
  id: 1,
  name: 'John',
  accounts: {
    facebook: {
      id: 'facebook',
      url: '/'
    },
    twitter: {
      id: 'twitter',
      url: '/'
    }
  }
};

我们需要修改其Twitter帐户URL并将其分配给新状态而不会影响当前状态,因此我们会做类似的事情

const newState = {
  ...state,
  accounts: { ...state.accounts, twitter: { 
  ...state.accounts.twitter, url: '/newUrl' } }
};

此代码有两个主要问题

  1. 与其目的相比,我只想更新一个属性。
  2. 可读性不是很好,为什么我只在更新一个属性时看到许多属性和嵌套级别?!

如果我们使用Immerjs,那就像这个

const newState = produce(state, (draftState) => {
  draftState.accounts.twitter.url = '/newUrl';
});

在这里,我们可以看到

  1. 较短的代码
  2. 更可读性,我只看到我正在更改的属性!

因此,Immerjs生产函数创建对象或数组的新草稿副本,并让您根据需要进行修改,然后通过应用更改返回新状态。

在反应中

所有状态都是不可变的,当我们设置一个状态时,我们创建一个新变量并将其分配给状态,我们不会更改当前一个

让我们有一个示例

const [quiz, setQuiz] = useState({
   title: "Quiz 1",
   questions: [
      {
        id: "1",
        type: "mcq",
        title: "Question 1?",
        answers: [
           {
             id: "a_1",
             text: "Answer 1",
             isTrue: true
           },
           {
             id: "a_2",
             text: "Answer 2",
             isTrue: false
           }
        ]
      }
   ]
});

我们已经拥有一个对象,如果我们想向测验推出新答案怎么办?我们会做这样的事情

const changeAnswer = (questionId, newAnswer) => {
  setQuiz({
    ...quiz,
    questions: quiz.questions.map((question) =>
      question.id === questionId
        ? { ...question, answers: [...question.answers, 
         newAnswer] }
        : question
    )
  });
};

复杂,对吗?这是使用Immerjs
完成的方式

const changeAnswer = (questionId, newAnswer) => {
  setQuiz(produce(prev, (draft) => {
      const question = draft.questions.find((el) => el.id === questionId);
      question.answers.push(newAnswer);
    }
  );
};

因此,这不仅仅是减少代码数量,而且我们只关注我们需要更改“答案”的内容,而不必关心其他测验属性。

还有一个灯软件包使用 - 以immer 包含一个自定义挂钩使用器,它用于使用usestate以自动调用state state state

const [quiz, setQuiz] = useImmer({
   .....
});

它将使我们的代码更简单

const changeAnswer = (questionId, newAnswer) => {
  setQuiz((draft) => {
    const question = draft.questions.find((el) => el.id === questionId);
    question.answers.push(newAnswer);
  });
};

这个很棒的软件包immerjs使redux工具包比旧的redux模式要简单得多,它是在此处自动实现的,因此您无需使用许多扩展操作员来更改还原器中的一个值。

非常感谢!