确保没有空值的最佳方法是什么

时间:2019-08-30 21:15:36

标签: javascript reactjs

这个问题可能更多是关于见解,而不是事实,但是我不确定我是否会问。

我正在构建一些将显示数据并允许进行编辑的表格,字段数据来自props(因为父组件正在使用GraphQL查询来提取更大的数量并传递给每个孩子)。

我发现一些输入数据正在评估为null(因为它没有从查询中传回),这会引发警告,因为输入不喜欢被分配为null值。

我的问题是,传递这些值时,对每个变量进行检查并在需要时分配空字符串的最干净方法是什么?

到目前为止,我尝试过的两个选项是:

有条件地将每个对象分配给状态对象,但这感觉很笨拙,并且代码很多:

const [state, setState] = useState({
    telephone: props.telephone ? props.telephone : '',
    nickname: props.nickname ? props.nickname : ''
    etc...
});

或者定义一个在设置状态之前映射道具并检查值的函数:

useEffect( () => {
    let state_arr = {};
    Object.keys(props).map( (key) => {
        if( !props[key] ) state_arr[key] = '';
        else state_arr[key] = props[key];
    } );
    setState(state_arr);
}, [] )

老实说,这感觉比第一种方法更干净,但是会在很多地方发生这种情况,因此必须在每种情况下都这样做会产生反作用。

任何帮助/见解表示赞赏。

5 个答案:

答案 0 :(得分:1)

编辑: 。事实证明,OP为此使用了材料UI。意味着,输入显示警告的原因是由于使用PropTypes的材料UI。我建议OP为<Input />组件创建一个包装器,并传递所有道具。在包装器组件内部,您可以执行以下操作:<InputWrapper value={props.value || ""} {...rest} />,其中涵盖了所有内容。

Live Demo

InputWrapper:

import React from 'react';
import { Input } from '@material-ui/core';

export default function InputWrapper({ value, ...rest }) {
  return <Input value={value || ""} {...rest} />
}

正在使用InputWrapper:

import React, { useState, useEffect } from 'react';
import { render } from 'react-dom';
import InputWrapper from './InputWrapper.js';


function App(props) {
  const [state, setState] = useState({});

  useEffect(() => {
    setState({
      name: props.name,
      age: props.age,
      hairColor: props.hairColor,
    })
  }, [props.name, props.age, props.hairColor]);

  const handleChange = (event, inputType) => {
    setState({...state, [inputType]: event.target.value})
  }

  return(
    <div>
      {/* Shows that you can pass through native <Input /> props: */}
      {/* state.name is null here! Warning is NOT thrown in the console! */}
      <InputWrapper value={state.name} fullWidth onChange={e => setState({...state, name: e.target.value})} />
      <InputWrapper value={state.name} multiline onChange={e => setState({...state, name: e.target.value})} />

      {Object.keys(state).map((item, index) => {
        return (
          <div>
            <InputWrapper 
              key={`${item}_${index}`} 
              value={state[item]} 
              onChange={e => handleChange(e, item)} />
          </div>
        );
      })}
    </div>
  );
}

render(
  <App name={null} age={44} hairColor="blue" />, 
  document.getElementById('root')
);

原始答案:

您的用例是什么?没有理由运行检查并分配空字符串...

如果您要强制使用某些属性,请查看PropTypes ...如果您不想强制使用某些道具,我建议您在使用时检查一个值变量。即使最初将其设置为空字符串,您仍然可能会遇到一些错误-我不明白您从空字符串中获得了什么。

我不了解用例-您能否详细说明为什么需要将其设置为空字符串?

如果您确实愿意,可以验证:useState({two: props.two || ""}) ...但是仍然没有必要。

// Notice how prop "two" is not being used..

function Test(props) {
  const [state, setState] = React.useState({
    one: props.one,
    two: props.two
  })
  
  return(
    <div>
      <p>{state.one}</p>
      <p>Even though <code>state.two</code> does not exist, there are no errors.. (at least for this demonstration)</p>
      <input type="text" value={state.two} />
      <input type="text" value={state.two} defaultValue={"default"} />
      <p><i>If you really wanted to, you could verify like:</i><code>useState(&#123;two: props.two || ""&#125;)</code><i>...but it is still unnecessary..</i></p>
    </div>
  );
}

ReactDOM.render(<Test one="I AM ONE" />, document.body)
code {
  margin: 0 10px;
  padding: 3px;
  color: red;
  background-color: lightgray;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.9.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>

答案 1 :(得分:0)

制作方法KickOutNullValues()可以做什么,然后可以在需要的地方重复使用。那会更优雅。

答案 2 :(得分:0)

这是一个棘手的问题,我不知道正确的答案。您已经尝试了两种方法,通常我会做的另一种方法是

如果您只是想正确显示,我会做

   <Telephone data={props.telephone} />,
   const Telephone = ({data}) => { if (!data) return null }

我发现这是为了允许子组件确保此问题的有效性,而不是在父API级别中整理数据。

   Telephone.defaultProps = {
     data: ''
   }

这进一步确保了如果数据为空,则defaultProps

会将其重置为”。

我大多数时候喜欢这种方式的原因是,我真的不想弄乱API数据的来源TRUTH。

当然,如果您确实想确保数据始终有效,则可能会更好:)

答案 3 :(得分:0)

如果将原始算法放入回调中,您的代码将开始具有类似意大利面条的品质。我建议在外面写一个function

您对Array#map的使用是不正确的,或者您正在以一种意想不到的方式使用它。 Array#map用于构造一个全新的数组。您正在模拟Array#forEach。另外,您正在执行假条件检查。 null是JavaScript中被视为false的众多值之一。即,您的痛点可能是undefined0''。如果唯一无效的返回值是null,请显式检查null

您打算使用的用例的枚举数为Array#reduce

function nullValueReplacer(obj) {
  return Object.entries(obj).reduce((newStateArr, [currentKey, currentValue]) => {
    if (currentValue === null) {
      newStateArr[currentKey] = ''
    } else {
      newStateArr[currentKey] = currentValue
    }
    return newStateArr
  }, {});
}

作为旁注,您可能需要更新变量名。您有一个名为state_arr的变量是一个对象,这很具有欺骗性。

答案 4 :(得分:0)

对象数组-修复不大

您不应在地图上使用钥匙。

考虑一下:(类似于您的)

useEffect(() => {
  let state_arr = Object.keys(props).map(prop =>  prop ? {prop} : { prop: '' });
  setState(state_arr);
}, [])

通过使用此代码,您可以创建带有对象的数组,并且可以轻松访问每个项目

如果没有昵称,它将看起来像这样:

[{ telephone: '245-4225-288' }, { nickname: '' }]

你怎么看?