阵列状态更新后,React不重新渲染

时间:2019-09-11 10:20:08

标签: javascript arrays reactjs gatsby

我有一个从数组呈现的复选框列表UI。更新阵列后,复选框列表状态不会更新。

我将代码移动到映射列表的位置,但是它不会更改结果。不会发生DOM重新渲染,请参见下面的gif。

我一直在寻找周围的事物,但我发现已经报告了此问题,但是关于将list.map代码移出其功能的解决方案对我不起作用。

您能给我建议一个解决方案吗? 这个问题的根源是什么?

This is the current state

import React,{ useState } from "react"

import
{
    Box,
    DropButton,
    Grid,
    Text,
    Calendar,
    RangeInput,
    CheckBox
} from "grommet"

const CalButton = ( { label,onSelect } ) =>
{
    return (
        <DropButton
            label={ label }
            dropAlign={ { top: 'bottom',left: 'left' } }
            margin="small"
            dropContent={
                <Box pad="medium" background="ligth-3" elevation="small">
                    <Calendar range size="medium" onSelect={ onSelect } />
                </Box>
            } />
    )
}

const RangeButton = ( { label,value,onChange,min,max,step,unit,header } ) =>
{

    return (
        <DropButton
            label={ value === null ? label : value + ' ' + unit }
            dropAlign={ { top: 'bottom',left: 'left' } }
            margin="small"
            dropContent={
                <Box pad="medium"
                    background="ligth-3"
                    elevation="small"
                    align="center"
                >
                    <Text size="small">{ header }</Text>
                    <RangeInput
                        value={ value }
                        min={ min } max={ max }
                        onChange={ onChange }
                        step={ step }
                    />
                    <Text weight="bold">{ value }</Text>
                    <Text weight="normal">{ unit }</Text>

                </Box>
            } />
    )
}

const FeaturesButton = ( { label,features,onChange } ) =>
{
    const FeaturesList = ( { features,onChange } ) => (
        <>
            { features.map( ( item,idx ) => (
            <CheckBox
                key={ item.name }
                label={ item.name }
                checked={ item.checked }
                onChange={ e => onChange( e,idx ) } />) 
                )
            }
        </>
    )



    return (
        <DropButton
            label={ label }
            dropAlign={ { top: 'bottom',left: 'left' } }
            margin="small"
            dropContent={
                <Box pad="medium"
                    background="ligth-3"
                    elevation="small"
                    align="start"
                    direction="column"
                    gap="small"
                >
                    <FeaturesList 
                        features={features} 
                        onChange={onChange} />

                </Box>
            } />
    )
}


const destApp = () =>
{

    const [ windStrength,setWindStrength ] = useState( null )
    const [ windFrequency,setWindFrequency ] = useState( null )
    const [ cost,setCost ] = useState( null )

    const date = new Date()
    const [ month,setMonth ] = useState( date.getMonth() )

    const [ listFeatures,setListFeatures ] = useState( [
        {
            name: 'Butter flat water',
            checked: false,
        },
        {
            name: 'Moderately flat water',
            checked: false,
        },
        {
            name: '1-2m Waves',
            checked: false,
        },
        {
            name: '2m+ Waves',
            checked: false,
        },
        {
            name: 'Beginer Friendly',
            checked: false,
        },
        {
            name: 'Kite-in-kite-out',
            checked: false,
        },
        {
            name: 'Nightlife',
            checked: false,
        }

    ] )
    const months = [ 'January','February','March','April','May','June','July','August','September','October','November','December' ];

    const updateFeaturesList = ( e,idx ) =>
    {

        listFeatures[ idx ].checked = e.target.checked
        const newFeatures = listFeatures
        setListFeatures( newFeatures )
        console.log( "Updated features list",newFeatures,e.target.checked )
    }

    return (
        <Grid rows={ [ "xsmall","fill" ] }
            areas={ [ [ "filterBar" ],[ "results" ] ] }
            gap="xxsmall">
            <Box gridArea="filterBar"
                direction="row-responsive"
                gap="xsmall"
                pad="xsmall"
                justify="center" >
                <CalButton label={ months[ month ].toLowerCase() } onSelect={ ( data ) => console.log( data ) } />
                <RangeButton
                    label="wind strength"
                    header="What's your wind preference?"
                    min="15"
                    max="45"
                    unit="kts"
                    value={ windStrength }
                    step={ 1 }
                    onChange={ ( e ) =>
                    {
                        setWindStrength( e.target.value )
                        console.log( windStrength )
                    } } />
                <RangeButton
                    label="wind frequency"
                    header="How often does your destination need to be windy?"
                    min="1"
                    max="7"
                    unit="days/week"
                    value={ windFrequency }
                    step={ 1 }
                    onChange={ ( e ) =>
                    {
                        setWindFrequency( e.target.value )
                        console.log( windFrequency )
                    } } />
                <RangeButton
                    label="cost"
                    header="Average daily cost: 1 lunch, diner and doubble room at a midrange hotel?"
                    min="10"
                    max="400"
                    unit="€"
                    value={ cost }
                    step={ 1 }
                    onChange={ ( e ) =>
                    {
                        setCost( e.target.value )
                        console.log( cost )
                    } } />

                <FeaturesButton
                    label="important features "
                    features={ listFeatures }
                    onChange={ updateFeaturesList }
                />
            </Box>
            <Box gridArea="results"
                margin="">
                Results go in here!

            </Box>


        </Grid>

    )
}

export default destApp 

2 个答案:

答案 0 :(得分:1)

您正在updateFeaturesList函数中改变原始状态。使用setState的功能形式来更新您当前的功能列表:

const updateFeaturesList = (e, idx) => {
  const { checked } = e.target;
  setListFeatures(features => {
    return features.map((feature, index) => {
      if (id === index) {
        feature = { ...feature, checked };
      }

      return feature;
    });
  });
};

还要注意,由于设置状态是异步的,因此在设置状态后立即调用console.log("Updated features list", newFeatures,e.target.checked)不会显示更新后的状态。

答案 1 :(得分:1)

问题出在private class LineChartFormatter: NSObject, IAxisValueFormatter { var labels: [String] = [] let dateFormatter = DateFormatter() let dateShortFormatter = DateFormatter() func stringForValue(_ value: Double, axis: AxisBase?) -> String { if let date = dateFormatter.date(from:labels[Int(value)]) { if value == 0 { dateShortFormatter.dateFormat = "MMM dd" return dateShortFormatter.string(from: date) } else { let prevDate = dateFormatter.date(from:labels[Int(value - 1)]) dateShortFormatter.dateFormat = "MMM" if dateShortFormatter.string(from: date) != dateShortFormatter.string(from: prevDate!) { dateShortFormatter.dateFormat = "MMM dd" return dateShortFormatter.string(from: date) } else { dateShortFormatter.dateFormat = "dd" return dateShortFormatter.string(from: date) } } } else { return labels[Int(value)] } } init(labels: [String]) { super.init() dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z" self.labels = labels }} 中,您直接在此行updateFeaturesList中对状态进行了更改,状态引用保持不变,因此react不知道是否应该重新呈现。

您可以做的就是在更改状态之前复制状态:

listFeatures[ idx ].checked = e.target.checked