最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React - change css style in one specific state - Stack Overflow

programmeradmin1浏览0评论

What I want to do is to change the border on the input to red if the input value doesn't match any movie in the API call. The user types in the input field and the call to the API shows the matching result. If we don't have any result I would like the border on the input to be red. But I can't see how I should make that happen.

The ponent Input is at the end of the code snippet.

CSS

.input-style {
  padding: 7px;
  border-radius: 5px;
  border: 1px solid #cccccc;
  font-family: Courier New, Courier, monospace;
  transition: background-color 0.3s ease-in-out;
  outline: none;
}
.input-style:focus {
  border: 1px solid turquoise;
}

APP.js

class App extends Component {
  constructor() {
    super();

    this.state = {
      value: '',
      items: [],
      isLoading: false,
      searchResult: null,
      error: false,
    };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  // To handle search
  handleChange(e) {
    this.setState({ value: e.target.value });
  }
  handleSubmit(e) {
    let searchResult = [];
    for (var i = 0; i < this.state.items.length; i++) {
      if (
        this.state.items[i].name
          .toLowerCase()
          .indexOf(this.state.value.toLowerCase()) !== -1
      ) {
        searchResult.push(this.state.items[i]);
      } else {
        console.log('No matches on your search, try again');
      }
    }
    e.preventDefault();

    // If we have something in the object searchResult
    if (searchResult.length > 0) {
      this.setState({
        error: false,
        value: '',
        searchResult: searchResult,
      });
    } else {
      this.setState({
        error: true,
        value: '',
        searchResult: [],
      });
    }
  }

  // call to the API
  ponentDidMount() {
    this.setState({ isLoading: !this.state.isLoading });
    fetch('')
      .then(response => response.json())
      .then(data => {
        this.setState({
          items: data,
          error: false,
        });
        this.setState({ isLoading: !this.state.isLoading });
      })
      .catch(console.error);
  }

  render() {
    return (
      <div className="App">
        <Header />

        <Loader isLoading={this.state.isLoading} />

        <Input
          handleChange={this.handleChange}
          handleSubmit={this.handleSubmit}
          value={this.state.value}
        />

        {this.state.error ? (
          <p className="errorMsg">No match on the search, try again!</p>
        ) : null}

        <Search search={this.state.searchResult} />
      </div>
    );
  }
}

export default App;

Input.js

function Input(props) {
  return (
    <div>
      <form onSubmit={props.handleSubmit}>
        <input
          type="text"
          className="input-style"
          placeholder="Sök efter film.."
          value={props.value}
          onChange={props.handleChange}
        />

        <button id="bold" className="button-style" type="submit">
          <i className="fa fa-search" />
        </button>
      </form>
    </div>
  );
}
export default Input;

What I want to do is to change the border on the input to red if the input value doesn't match any movie in the API call. The user types in the input field and the call to the API shows the matching result. If we don't have any result I would like the border on the input to be red. But I can't see how I should make that happen.

The ponent Input is at the end of the code snippet.

CSS

.input-style {
  padding: 7px;
  border-radius: 5px;
  border: 1px solid #cccccc;
  font-family: Courier New, Courier, monospace;
  transition: background-color 0.3s ease-in-out;
  outline: none;
}
.input-style:focus {
  border: 1px solid turquoise;
}

APP.js

class App extends Component {
  constructor() {
    super();

    this.state = {
      value: '',
      items: [],
      isLoading: false,
      searchResult: null,
      error: false,
    };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  // To handle search
  handleChange(e) {
    this.setState({ value: e.target.value });
  }
  handleSubmit(e) {
    let searchResult = [];
    for (var i = 0; i < this.state.items.length; i++) {
      if (
        this.state.items[i].name
          .toLowerCase()
          .indexOf(this.state.value.toLowerCase()) !== -1
      ) {
        searchResult.push(this.state.items[i]);
      } else {
        console.log('No matches on your search, try again');
      }
    }
    e.preventDefault();

    // If we have something in the object searchResult
    if (searchResult.length > 0) {
      this.setState({
        error: false,
        value: '',
        searchResult: searchResult,
      });
    } else {
      this.setState({
        error: true,
        value: '',
        searchResult: [],
      });
    }
  }

  // call to the API
  ponentDidMount() {
    this.setState({ isLoading: !this.state.isLoading });
    fetch('https://api.tvmaze./shows')
      .then(response => response.json())
      .then(data => {
        this.setState({
          items: data,
          error: false,
        });
        this.setState({ isLoading: !this.state.isLoading });
      })
      .catch(console.error);
  }

  render() {
    return (
      <div className="App">
        <Header />

        <Loader isLoading={this.state.isLoading} />

        <Input
          handleChange={this.handleChange}
          handleSubmit={this.handleSubmit}
          value={this.state.value}
        />

        {this.state.error ? (
          <p className="errorMsg">No match on the search, try again!</p>
        ) : null}

        <Search search={this.state.searchResult} />
      </div>
    );
  }
}

export default App;

Input.js

function Input(props) {
  return (
    <div>
      <form onSubmit={props.handleSubmit}>
        <input
          type="text"
          className="input-style"
          placeholder="Sök efter film.."
          value={props.value}
          onChange={props.handleChange}
        />

        <button id="bold" className="button-style" type="submit">
          <i className="fa fa-search" />
        </button>
      </form>
    </div>
  );
}
export default Input;
Share Improve this question edited Jun 20, 2018 at 7:29 Joshua 3,1963 gold badges26 silver badges41 bronze badges asked Jun 20, 2018 at 7:13 LaconLacon 1051 gold badge3 silver badges12 bronze badges 1
  • 3 You can change the className conditionally. stackoverflow./questions/30533171/… – Abin Thaha Commented Jun 20, 2018 at 7:16
Add a ment  | 

3 Answers 3

Reset to default 3

You can pass the error into the Input ponent from the App

<Input
   handleChange={this.handleChange}
   handleSubmit={this.handleSubmit}
   value={this.state.value}
   error={this.state.error)
/>

and in your Input ponent:

 <input
   type="text"
   className={props.error ? 'error-input-style' : 'input-style'}
   placeholder="Sök efter film.."
   value={props.value}
   onChange={props.handleChange}
 />

alternative you can also set an inline styling for the error condition:

 <input
   type="text"
   className="input-style"
   placeholder="Sök efter film.."
   value={props.value}
   onChange={props.handleChange}
   style={{ border: props.error ? '1px solid red' : '' }}
 />

You can easily do this. Have a flag, say resultFound, in the state of App.js, with an initial value of false. Then, in the function where you make the API call, update this resultFound depending on whether any result was obtained.

And, in the render(), before returning, assign inputClassName dynamically based on the this.state.resultFound, like so,

let inputClassName = '';
if (this.state.resultFound === false) {
  inputClassName = 'input-style-error';       // new CSS class for errors
} else {
  inputClassName = 'input-style';
}

Then, you can pass the inputClassName as a prop to Input and use it as <input>'s className, like so,

// in your App.js render() method's return
// ... existing ponents
<Input customStyle={inputClassName} ... />
// ...
<!-- in your Input.js render() method -->
<input type="text" className={props.customStyle} ... />

Whenever the API call happens, your state will change causing a re-render of the DOM (render() is called). During each call, we dynamically set the inputClassName based on the state's resultFound. And, accordingly, the right className will be applied to the <input>.

I will give bad names for classes and variables, just to make it super clear. You should use more generic ones.

The trick here is to give your Input a dynamic class via props, and if that expression turns true and the class is appended to the element, you can style it with css.

__CSS__

    .input-style {
      padding: 7px;
      border-radius: 5px;
      border: 1px solid #cccccc;
      font-family: Courier New, Courier, monospace;
      transition: background-color 0.3s ease-in-out;
      outline: none;
    }
    .input-style:focus {
      border: 1px solid turquoise;
    }
    .input-style.red-border {
      border: 1px solid red;
    }

__APP.js__   

    class App extends Component {
      constructor() {
        super();

        this.state = {
          value: '',
          items: [],
          isLoading: false,
          searchResult: null,
          error: false,
        };
        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
      }

      // To handle search
      handleChange(e) {
        this.setState({ value: e.target.value });
      }
      handleSubmit(e) {
        let searchResult = [];
        for (var i = 0; i < this.state.items.length; i++) {
          if (
            this.state.items[i].name
              .toLowerCase()
              .indexOf(this.state.value.toLowerCase()) !== -1
          ) {
            searchResult.push(this.state.items[i]);
          } else {
            console.log('No matches on your search, try again');
          }
        }
        e.preventDefault();

        // If we have something in the object searchResult
        if (searchResult.length > 0) {
          this.setState({
            error: false,
            value: '',
            searchResult: searchResult,
          });
        } else {
          this.setState({
            error: true,
            value: '',
            searchResult: [],
          });
        }
      }

      // call to the API
      ponentDidMount() {
        this.setState({ isLoading: !this.state.isLoading });
        fetch('https://api.tvmaze./shows')
          .then(response => response.json())
          .then(data => {
            this.setState({
              items: data,
              error: false,
            });
            this.setState({ isLoading: !this.state.isLoading });
          })
          .catch(console.error);
      }

      render() {
        return (
          <div className="App">
            <Header />

            <Loader isLoading={this.state.isLoading} />

            <Input
              handleChange={this.handleChange}
              handleSubmit={this.handleSubmit}
              value={this.state.value}
              showRedBorder={this.state.error === true} // or what ever your logic
            />

            {this.state.error ? (
              <p className="errorMsg">No match on the search, try again!</p>
            ) : null}

            <Search search={this.state.searchResult} />
          </div>
        );
      }
    }

    export default App;

__Input.js__

    function Input(props) {
      return (
        <div>
          <form onSubmit={props.handleSubmit}>
            <input
              type="text"
              className={`input-style${props.showRedBorder ? ' red-border' : ''}`}
              placeholder="Sök efter film.."
              value={props.value}
              onChange={props.handleChange}
            />

            <button id="bold" className="button-style" type="submit">
              <i className="fa fa-search" />
            </button>
          </form>
        </div>
      );
    }
    export default Input;
发布评论

评论列表(0)

  1. 暂无评论