Search code examples
javascriptreactjsecmascript-6react-functional-component

Return the same Div when clicking + button in React JS


i build this div element here , which at the end has a "+" button and a "x" button . The plus button adds the same div just below it and the x or clear button removes it . Now how can i render the same div when clicking plus button or when clicking x , i tried multiple ways but i couldn't do it , this is my code. One way that i think of is doing recursion but it doesn't work.

enter image description here

function IpRangeInput() {
  const [ipRange, setIpRange] = useState<string>('');
  const [inputValue, setInputValue] = useState<string>('');
  const [fromValue, setFromValue] = useState<string>('');
  const [toValue, setToValue] = useState<string>('');

  const handleInputValue = (event: React.ChangeEvent<HTMLInputElement>) => {
    setInputValue(event?.target.value);
  };

  const handleAdd = () => <IpRangeInput />;

  return (
    <Box className={styles.inputContainer}>
      <ThemeProvider theme={theme}>
        <FormControl className={styles.inputContainer__select}>
          <Select
            defaultValue="Select"
            id="select-label"
            value={ipRange}
            onChange={(e) => setIpRange(e.target.value)}
          >
            <MenuItem value="IP/CIDR">IP / CIDR</MenuItem>
            <MenuItem value="Range">Range</MenuItem>
          </Select>
        </FormControl>

        {ipRange === 'Range' ? (
          <>
            <span className={styles.inputContainer__text}>From</span>
            <Box
              className={[
                styles.inputContainer__input,
                styles.inputContainer__newInput,
              ].join(' ')}
            >
              <TextField
                value={fromValue}
                onChange={(e) => setFromValue(e.target.value)}
              />
            </Box>

            <span className={styles.inputContainer__text}>To</span>
            <Box
              className={[
                styles.inputContainer__input,
                styles.inputContainer__newInput,
              ].join(' ')}
            >
              <TextField
                value={toValue}
                onChange={(e) => setToValue(e.target.value)}
              />
            </Box>
          </>
        ) : (
          <Box className={styles.inputContainer__input}>
            <TextField value={inputValue} onChange={handleInputValue} />
          </Box>
        )}

        <IconButton
          className={styles.inputContainer__addButton}
          onClick={handleAdd}
        >
          <AddIcon />
        </IconButton>

        <IconButton
          className={styles.inputContainer__clearButton}
          onClick={handleAdd}
        >
          <Clear />
        </IconButton>
      </ThemeProvider>
    </Box>
  );
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>


Solution

  • Вам нужно хранить список блоков в родительском компоненте в стейте, например, как массив айди. Каждому блоку присваивается свой айди. И в итоге нажатие кнопок будет триггерить удаление или добавление айди в массив или из него

    Ваш итоговый код:

    function Parent () {
      const [list, setList] = useState([0])
      
      const handleAdd = (id) => setList(prevList => prevList.push(id + 1))
    
      const handleClear = (id) => setList(prevList => {
        prevList.splice(id, 1)
        return prevList
      })
    
      return (
        list.map((item) => {
          <IpRangeInput
            key={item}
            id={item}
            handleAdd={handleAdd}
            handleClear={handleClear}
          />
        })
      )
    }
    
    function IpRangeInput({ handleAdd, handleClear, id }) {
      const [ipRange, setIpRange] = useState<string>('');
      const [inputValue, setInputValue] = useState<string>('');
      const [fromValue, setFromValue] = useState<string>('');
      const [toValue, setToValue] = useState<string>('');
    
      const handleInputValue = (event: React.ChangeEvent<HTMLInputElement>) => {
        setInputValue(event?.target.value);
      };
    
      const handleAdd = () => handleAdd(id)
      const handleClear = () => handleAdd(id)
    
      return (
        <Box className={styles.inputContainer}>
          <ThemeProvider theme={theme}>
            <FormControl className={styles.inputContainer__select}>
              <Select
                defaultValue="Select"
                id="select-label"
                value={ipRange}
                onChange={(e) => setIpRange(e.target.value)}
              >
                <MenuItem value="IP/CIDR">IP / CIDR</MenuItem>
                <MenuItem value="Range">Range</MenuItem>
              </Select>
            </FormControl>
    
            {ipRange === 'Range' ? (
              <>
                <span className={styles.inputContainer__text}>From</span>
                <Box
                  className={[
                    styles.inputContainer__input,
                    styles.inputContainer__newInput,
                  ].join(' ')}
                >
                  <TextField
                    value={fromValue}
                    onChange={(e) => setFromValue(e.target.value)}
                  />
                </Box>
    
                <span className={styles.inputContainer__text}>To</span>
                <Box
                  className={[
                    styles.inputContainer__input,
                    styles.inputContainer__newInput,
                  ].join(' ')}
                >
                  <TextField
                    value={toValue}
                    onChange={(e) => setToValue(e.target.value)}
                  />
                </Box>
              </>
            ) : (
              <Box className={styles.inputContainer__input}>
                <TextField value={inputValue} onChange={handleInputValue} />
              </Box>
            )}
    
            <IconButton
              className={styles.inputContainer__addButton}
              onClick={handleAdd}
            >
              <AddIcon />
            </IconButton>
    
            <IconButton
              className={styles.inputContainer__clearButton}
              onClick={handleClear}
            >
              <Clear />
            </IconButton>
          </ThemeProvider>
        </Box>
      );
    }