Как получить значение значения вложенного элемента ввода из моего собственного компонента реагирования в изолированном файле?

У меня есть «Мой компонент React» следующим образом:

'use client';

import styles from './range-slider.module.css'

// range input = track & thumb

export default function RangeSlider({minState, maxState} : 
    {minState: [string, Function], maxState: [string, Function]}) {
  const [min, setMin] = minState;
  const [max, setMax] = maxState;

  const handleMin = (e: React.ChangeEvent<HTMLInputElement>) => {
    setMin(parseInt(e.target.value) < parseInt(max)? e.target.value : max);
  };

  const handleMax = (e: React.ChangeEvent<HTMLInputElement>) => {
    setMax(parseInt(e.target.value) > parseInt(min)? e.target.value : min);
  };

  return (
    <div>
      <div className = {styles.rangeInput}>
        <div className = {styles.sliderCtrl}>
          <input 
            type = "range" 
            className = {`${styles.slider} ${styles.min}`} 
            min = "0" 
            max = "100"
            value = {min}
            onChange = {handleMin}/>
          <input 
            type = "range" 
            className = {`${styles.slider} ${styles.max}`} 
            min = "0" 
            max = "100"
            value = {max}
            onChange = {handleMax}/>
        </div>
        <div className = {styles.inputCtrl}>
          <div className = "min">
            <input 
              className = "val-input" 
              type = "number" 
              min = "0" 
              max = "100"
              value = {min}
              onChange = {handleMin}/>
          </div>
          <div className = "max">
            <input 
              className = "val-input" 
              type = "number" 
              min = "0" 
              max = "100"
              value = {max}
              onChange = {handleMax}/>
          </div>
        </div>
      </div>
    </div>
  )
}

Однако я подозреваю, что передавать useState в качестве реквизита в RangeSlider — не лучшая практика. Мой вопрос 1: является ли это хорошей практикой и как можно это сделать.

Фактически, моя основная цель — просто получить значение RangeSlider (т. е. значение двух входных значений диапазона, вложенных в него) из его родительского компонента, я благодарен, если кто-нибудь может рассказать мне что-нибудь об этом, и это вопрос 2.

Предпосылка того, что вы делаете, абсолютно хороша. Синтаксис, возможно, немного неуклюж. Я предпочитаю передавать конкретные имена свойств, а не просто передавать состояние напрямую (даже если результат будет идентичным). Рекомендуется передавать 4 явных имени реквизита — minValue, maxValue, onChangeMin и onChangeMax. Возможно, вы могли бы переместить логику этого компонента обработки изменений значений в родительский компонент. Однако при этом вы не допустили никаких вопиющих ошибок.

Adam Jenkins 18.04.2024 04:14

Что касается машинописного текста, не используйте Function, а вместо этого определите сигнатуру функции (value: number) => void. Опять же, это не огромная проблема, а просто улучшение. Я подозреваю, что отрицательный голос поступил от кого-то, кто думал, что это вопрос, основанный на мнении, и он принадлежит сайту проверки кода, поскольку у вас нет конкретной проблемы, с которой вы обращаетесь за помощью.

Adam Jenkins 18.04.2024 04:18

@Адам Дженкинс Спасибо за подробный ответ и самоотверженность :). Хотя я, наконец, не принял ответ, но думаю, что почерпнул знания из вашего комментария и ответа.

Tel lui 25.04.2024 08:18
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
3
176
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

используйте хук useRef для ссылки на входной элемент и получения того, что вы хотите.

 import React, { useRef } from 'react';
 import styles from './range-slider.module.css';
    
export default function RangeSlider({ minState, maxState }) {
  const [min, setMin] = minState;
  const [max, setMax] = maxState;
  
  // Create refs for min and max inputs
  const minInputRef = useRef(null);
  const maxInputRef = useRef(null);

  const handleMin = (e) => {
    const value = parseInt(e.target.value);
    setMin(value < parseInt(max) ? value : max);
  };

  const handleMax = (e) => {
    const value = parseInt(e.target.value);
    setMax(value > parseInt(min) ? value : min);
  };

  return (
    <div>
      <div className = {styles.rangeInput}>
        <div className = {styles.sliderCtrl}>
          <input 
            type = "range" 
            className = {`${styles.slider} ${styles.min}`} 
            min = "0" 
            max = "100"
            value = {min}
            onChange = {handleMin}
            ref = {minInputRef} 
          />
          <input 
            type = "range" 
            className = {`${styles.slider} ${styles.max}`} 
            min = "0" 
            max = "100"
            value = {max}
            onChange = {handleMax}
            ref = {maxInputRef} 
          />
        </div>
        <div className = {styles.inputCtrl}>
          <div className = "min">
            <input 
              className = "val-input" 
              type = "number" 
              min = "0" 
              max = "100"
              value = {min}
              onChange = {handleMin}
              ref = {minInputRef} 
            />
          </div>
          <div className = "max">
            <input 
              className = "val-input" 
              type = "number" 
              min = "0" 
              max = "100"
              value = {max}
              onChange = {handleMax}
              ref = {maxInputRef} 
            />
          </div>
        </div>
      </div>
    </div>
  );
}

ОП прекрасно использует контролируемые входы. useRef необходим, когда вам нужно императивно получить значение и вы используете неконтролируемые входные данные. Это не верно.

Adam Jenkins 18.04.2024 11:36

что ты говоришь, как это неконтролируемый вход?

Rajeshkanth 24.04.2024 14:43

Смотрите мои комментарии, но я напишу это как ответ.

У вас уже есть значение в родительском компоненте.

Ваш родительский компонент (если посмотреть на API вашего RangeSlider) должен выглядеть примерно так:

const minState = useState(0);
const maxState = useState(100);

return (
   <RangerSlider minState = {minState} maxState = {maxState}/>
)

Это означает, что если вы хотите «захватить» значения в родительском компоненте, например, из-за обработчика событий, они уже есть в minState и maxState. Возьмите их вот так:

const minState = useState(0);
const maxState = useState(100);

const handleClick = () => {
   const minValueOfRangeSlider = minState[0];
   const maxValueOfRangeSlider = maxState[0];

   // do something with them
}

return (
   <>
    <RangerSlider minState = {minState} maxState = {maxState}/>
    <button onClick = {handleClick}>Submit</button>
   </>
)

реквизиты, которые вы передаете в качестве значения, должны быть добавлены в родительский элемент, поэтому на самом деле теперь у вас есть нужные значения, кроме того, вы можете добавить функцию handleChangeEvent к входам onChange в качестве реквизита, например:

export default function RangeSlider ({min, max, handleChangeEvent}: {min: string, max: string, handleChangeEvent: React.ChangeEvent<HTMLInputElement>}) {
return (
   <>
     <input defaultValue = {min} name = "min" onChange = {handleChangeEvent}/>
     <input defaultValue = {max} name = "max" onChange = {handleChangeEvent}/>
   </>
)

}

и в родительском элементе вы можете справиться с этим, используя эту функцию:

export default function ParentComponent() {

const [state, setState] = useState({
  min: 0,
  max: 0
})

const handleChangeEvent = (e) => {
 let { value, name} = e.target;
 setState({...state, [name]:value})
}
return (
  <>
    <RangeSlider min = {state.min} max = {state.max} handleChangeEvent = {handleChangeEvent} />
  </>

}

Ответ принят как подходящий

Совместное использование состояния

Чтобы разделить состояние между родительским компонентом и его дочерним компонентом, вы хотите, чтобы состояние «жило» в родительском компоненте, и вы хотите передать дочернему компоненту методы чтения и записи в это состояние.

Короче говоря, вы подходите к этому правильно.

Передача реквизитов состояния

Лучше всего явно передавать min, setMin, max и setMax в качестве реквизита. Это помогает сделать назначение каждого свойства более ясным. На практике, если ваш реквизит будет более плоским, это поможет вам избежать ошибок. Например, если бы вы когда-либо зависели от minState в use-хуке (маловероятно), вы можете обнаружить, что он обновляется чаще/реже, чем вы ожидаете, поскольку это будет зависеть от всего массива, а не только от элемента значения. .

Машинопись

Еще один совет: вы можете явно ввести функции set, используя те же типы, что и React. Вы могли бы использовать React.Dispatch<React.SetStateAction<T>> для представления функции setState для некоторого типа T.

Учитывая вышеизложенное, вот как я бы реорганизовал ваш код:

'use client';

import styles from './range-slider.module.css'

interface RangeSliderProps {
  max: string
  setMax: React.Dispatch<React.SetStateAction<T>>
  min: string
  setMin: React.Dispatch<React.SetStateAction<T>> 
}

export default function RangeSlider({ min, setMin, max, setMax }: RangeSliderProps) {
  const handleMin = (e: React.ChangeEvent<HTMLInputElement>) => {
    setMin(parseInt(e.target.value) < parseInt(max) ? e.target.value : max);
  };

  const handleMax = (e: React.ChangeEvent<HTMLInputElement>) => {
    setMax(parseInt(e.target.value) > parseInt(min) ? e.target.value : min);
  };

  return (
    <div>
      <div className = {styles.rangeInput}>
        <div className = {styles.sliderCtrl}>
          <input 
            type = "range" 
            className = {`${styles.slider} ${styles.min}`} 
            min = "0" 
            max = "100"
            value = {min}
            onChange = {handleMin}/>
          <input 
            type = "range" 
            className = {`${styles.slider} ${styles.max}`} 
            min = "0" 
            max = "100"
            value = {max}
            onChange = {handleMax}/>
        </div>
        <div className = {styles.inputCtrl}>
          <div className = "min">
            <input 
              className = "val-input" 
              type = "number" 
              min = "0" 
              max = "100"
              value = {min}
              onChange = {handleMin}/>
          </div>
          <div className = "max">
            <input 
              className = "val-input" 
              type = "number" 
              min = "0" 
              max = "100"
              value = {max}
              onChange = {handleMax}/>
          </div>
        </div>
      </div>
    </div>
  )
}

Другие вопросы по теме