如何使用香草JS复制useState

时间:2020-11-08 23:53:54

标签: javascript

Vanilla JS中的代码将实现什么,使我们能够像React中useState那样声明和更新状态:

new_tab

这个问题在JS上确实变得更好。天真地选择它是有意义的:

const [x, setX] = useState(12);
setX(14);
console.log(x); // 14

但是我不明白数组[x,setX]如何具有一个回调(setX),该回调在用const声明时会影响x?我希望这是有道理的。

3 个答案:

答案 0 :(得分:2)

您缺少一些非常重要的东西-所有react钩子都使用“支持”它们,这使您可以在没有实例而只有函数的情况下提供有效的实例变量。

React中的这个东西叫做光纤,它有效地代表了React组件的生命周期-它本身并不与函数本身相关,它与组件相关联,而React正在渲染(和重新渲染)。这就是为什么您可以拥有一个功能组件声明,多次渲染同一功能,并且每个功能组件都能够维护自己的状态的原因-状态不是功能的一部分,状态是React光纤的一部分。

但是我不明白数组[x,setX]如何具有回调(setX) 用const声明时可能会影响x?

在调用setX时,您并不仅仅是改变x的值,而是告诉React用新的x值重新渲染组件(光纤)。

strong>

编辑:

一个极其简单的示例,其中函数本身用作状态的后备实例(React中不是这种情况)可能看起来像这样:

// this line is example only so we can access the stateSetter external to the function
let stateSetter;

const states = new Map();

const useState = (value,context) => {
    const current = states.get(context.callee) || [value,v => {
            const currentState = states.get(context.callee);
            currentState[0] = typeof v === 'function' ? v(currentState[0]) : v        
            // we recall the function with the same arguments it was originally called with - "re-rendering it" of sorts...
            context.callee.call(context);
    }];
    states.set(context.callee,current);
    return current;

}

const MyFunction = function(value) {
    const [state,setState] = useState(value, arguments)
    stateSetter = setState;
    console.log('current value of state is: ',state)
}

MyFunction(10);
MyFunction(20); // state hasn't changed
stateSetter('new state'); // state has been updated!

答案 1 :(得分:1)

我也想学习如何做到这一点。 I found how to do it here。我重构了代码以改用 arrow functions,这会使代码片段更难阅读和理解。如果是这种情况,请前往以上链接中共享的资源。

这是实现:

const useState = (defaultValue) => {
  // ? We create a function useState with a default value
  let value = defaultValue;
  // ? We create a local variable value = defaultValue
  const getValue = () => value
  // ? We create a function to set the value with parameter newValue
  const setValue = newValue => value = newValue // ? We change the value for newValue
  return [getValue, setValue]; // ? We return an array with the value and the function
}

const [counter, setCounter] = useState(0);
// ? We destructure the array as a return of the useState function into two value

console.log(counter()); // ? returns 0 which it's the value of counter()

为了更容易理解,我添加了注释。这是没有注释的实现:

const useState = (defaultValue) => {
  let value = defaultValue;
  const getValue = () => value
  const setValue = newValue => value = newValue
  return [getValue, setValue];
}

const [counter, setCounter] = useState(0);

console.log(counter());

为了更好地阅读和理解,我使用 regular functions 包含了该代码段:

function useState(defaultValue) {
  let value = defaultValue

  function getValue() {
    return value
  }

  function setValue(newValue) {
    value = newValue
  }

  return [getValue, setValue];
}

const [counter, setCounter] = useState(0);

答案 2 :(得分:0)

使用构造函数模拟 useState() 的简单解决方案。这可能不是最好的解决方案,因为构造函数每次都返回函数的副本,但却解决了相关问题。

function Hook(){
  return function (initialState){
    this.state = initialState;
    return [
      this.state,
      function(newState){
        this.state = newState;
      }
    ];
  }
}
const useState = new Hook();

现在,解构 useState(),它是 Hook()

的一个实例
const [state, setState] = useState(0);
console.log(state); // 0
setState({x:20});
console.log(state); // { x: 20 }
setState({x:30});
console.log(state); // { x: 30 }