My problem is I do not really understand if using function components instead function is good idea in below example:
first program without function components
class App extends React.Component {
state = {
check: false,
isFormSubmitted: false
}
handleChangeChecked = () => {
this.setState({
check: !this.state.check,
isFormSubmitted: false
})
return (true)
}
displayMsg = () => {
if (this.state.isFormSubmitted == true) {
if (this.state.check == true)
return (<p>You are allowed to watch this film!</p>)
else return (<p>You are not allowed to watch this film.</p>)
} else return (null)
}
handleFormSubmit = (e) => {
e.preventDefault()
this.setState({
isFormSubmitted: true
})
}
render() {
return (
<React.Fragment>
<h1>Film</h1>
<form onSubmit={this.handleFormSubmit}>
<input type="checkbox" onChange={this.handleChangeChecked} checked={this.state.check} />
<label>I have got 16 years old</label>
<button>Buy ticket</button>
</form>
{this.displayMsg()}
</React.Fragment>
)
}
}
ReactDOM.render(< App />, document.getElementById('root'));
second program with function components:
const PositiveMessage = () => <p>Mozesz obejrzeć film, zapraszam</p>;
const NegativeMessage = () => <p>Nie możesz obejrzeć tego filmu !</p>;
class TicketShop extends React.Component {
state = {
isConfirmed: false,
isFormSubmitted: false
}
handleCheckboxChange = () => {
this.setState({
isConfirmed: !this.state.isConfirmed,
isFormSubmitted: false
})
}
displayMessage = () => {
if (this.state.isFormSubmitted) {
if (this.state.isConfirmed) { return <PositiveMessage /> }
else { return <NegativeMessage /> }
} else { return null }
}
handleFormSubmit = (e) => {
e.preventDefault()
if (!this.state.isFormSubmitted) {
this.setState({
isFormSubmitted: !this.state.isFormSubmitted
})
}
}
render() {
return (
<>
<h1>Kup bilet na horror roku !</h1>
<form onSubmit={this.handleFormSubmit}>
<input type="checkbox" id="age" onChange={this.handleCheckboxChange} checked={this.state.isConfirmed} />
<label htmlFor="age">Mam conajmniej 16 lat</label>
<br />
<button type="submit">Kup bilet</button>
</form>
{this.displayMessage()}
</>
)
}
}
ReactDOM.render(<TicketShop />, document.getElementById('root'))
i made two programs with and without function components and i dont see the difference of working.
In user point of view both programs works without any difference.
Related
Looking for thinking tips towards refactoring the App function. The component must remain unchanged. This example is clunky and a mashup of several different online contributions to the use of ref.
I started here: https://reactjs.org/docs/refs-and-the-dom.html
Thanks in advance.
class Username extends React.Component {
state = { value: "" };
changeValue(value) {
this.setState({ value });
}
render() {
const { value } = this.state;
return <h1>{value}</h1>;
}
}
function App() {
this.username = React.useRef();
this.component = React.useRef()
clickHandler = e => {
//console.log(this.component.current.changeValue())
this.component.current.changeValue(this.username.current.value)
}
return (
<div>
<button onClick={clickHandler}>Change Username</button>
<input type="text" ref={this.username}/>
<Username ref={this.component}/>
</div>
);
}
document.body.innerHTML = "<div id='root'></div>";
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
document.querySelector("input").value = "John Doe";
document.querySelector("button").click();
setTimeout(() => console.log(document.getElementById("root").innerHTML));
Try this code.
function Username({ value }) {
return (
<h1>{value}</h1>
);
}
class App extends React.Component {
state = {
usernameDynamic: '',
usernameStatic: '',
}
onChangeUserName = () => {
this.setState({ usernameStatic: usernameDynamic });
}
onChangeUserNameDynamic = (e) => {
this.setState({ usernameDynamic: e.target.value });
}
render() {
return (
<div>
<button onClick={this.onChangeUserNameStatic}>Change Username</button>
<input type="text" value={this.state.usernameDynamic} onChange={this.onChangeUserNameDynamic} />
<Username value={this.state.usernameStatic} />
</div>
);
}
}
I have 3 components:
Search.js, Customers.js and Customer.js
In Search.js I have an input field. I want to send whatever value entered in the field over to the Customer.js component. I thought this would be straightforward, but I was wrong ...
I have also a context.js component that stores state for the application (I don't want to use redux because I don't know it yet).
Sorry but this is gonna be a long post as I want to give the background for this specific situation:
context.js
const Context = React.createContext();
const reducer = (state, action) => {
switch (action.type) {
case "SEARCH_CUSTOMERS":
return {
...state,
customer_list: action.payload,
firstName: ''
};
default:
return state;
}
};
export class Provider extends Component {
state = {
customer_list: [],
firstName: "",
dispatch: action => this.setState(state => reducer(state, action))
};
componentDidMount() {
axios
.get("/api")
.then(res => {
console.log(res.data);
this.setState({ customer_list: res.data });
})
.catch(error => console.log(error));
}
render() {
return (
<Context.Provider value={this.state}>
{this.props.children}
</Context.Provider>
);
}
}
export const Consumer = Context.Consumer;
Search.js: the input value I want to send to Customer is 'firstName'
class Search extends Component {
state = {
firstName: ""
};
onChange = e => {
this.setState({ [e.target.name]: e.target.value });
};
findCustomer = (dispatch, e) => {
e.preventDefault();
axios
.get("/api/customers", {
params: {
firstName: this.state.firstName,
}
})
.then(res => {
dispatch({
type: "SEARCH_CUSTOMERS",
payload: res.data
});
this.setState({ firstName: "" });
});
};
return (
<Consumer>
{value => {
const { dispatch } = value;
return (
<form onSubmit={this.findCustomer.bind(this, dispatch)}>
<div className="form-group">
<input
ref={input => {
this.nameInput = input;
}}
type="text"
name="firstName"
value={this.state.firstName}
onChange={this.onChange}
/>
the Customers.js:
class Customers extends Component {
render() {
const key = Date.now();
return (
<Consumer>
{value => {
const { customer_list} = value;
if (customer_list === undefined || customer_list.length === 0) {
return <Spinner />;
} else {
return (
<React.Fragment>
<h3 className="text-center mb-4">{heading}</h3>
<div className="row">
{customer_list.map(item => (
<Customer key={item.key} customer={item} />
))}
</div>
</React.Fragment>
);
}
}}
</Consumer>
);
}
}
export default Customers;
and Finally theCustomer.js: this is where I want the input value to be displayed:
const Customer = props => {
const { customer } = props;
return (
<div className="col-md-12">
<div className="card-body">
<strong>{customer.firstName}</strong> // not working
...
}
the {customer.firstName} does not show the value.
Is is necessary to go through the intermediate Customers.js component to pass the input value?
I would like to keep the architecture as is (with the context.js) and display the value in the Customer.js component.
In the following code:
class App extends React.Component {
state = { val: '' };
handleChange = (e) => {
this.setState({ val: e.target.value });
}
OddEven(num) {
const number = parseInt(num);
let description;
if (Number.isInteger(number)) {
if (number % 2 == 0) {
description = <strong>even</strong>;
} else {
description = <i>odd</i>;
}
alert(number);
return (
<h1>
Test
</h1>
);
} else {
return null;
}
}
render() {
return (
<div>
<input type='text' onChange={this.handleChange} />
<button onClick={() =>this.OddEven(this.state.val) }>
Odd Even
</button>
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
the OddEven() is not returning the div. Can't figure out why for the last 2 hours. I'm in the learning phase. So don't get offended if it's something silly.
if you want to return your description here is how to do it:
class App extends React.Component {
state = {
val: '',
description: null,
};
handleChange = (e) => {
this.setState({ val: e.target.value });
}
OddEven(num) {
const number = parseInt(num);
let {description} = this.state;
if (Number.isInteger(number)) {
if (number % 2 == 0) {
description = <strong>even</strong>;
} else {
description = <i>odd</i>;
}
this.setState({description: description});
} else {
this.setState({description: null});
}
}
render() {
return (
<div>
<input type='text' onChange={this.handleChange} />
<button onClick={() =>this.OddEven(this.state.val) }>
Odd Even Check?
</button>
{this.state.description}
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
That is because you are not rendering what your function returns anywhere, what you would rather want to do is this:
class App extends React.Component {
state = { val: "", oddeven: "" }
handleChange = e => {
this.setState({ val: e.target.value })
}
OddEven = () => {
const number = parseInt(this.state.val) //Use the state directly
let description
if (Number.isInteger(number)) {
if (number % 2 == 0) {
description = <strong>even</strong>
} else {
description = <i>odd</i>
}
alert(number)
this.setState({ oddEven: "Hello" })
} else {
return null
}
}
render() {
return (
<div>
<input type="text" onChange={this.handleChange} />
<button onClick={this.OddEven}>Odd Even</button> {/* you do not need to passs the state here, you can directly access it in your function */}
{this.state.oddEven && <h1>{this.state.oddEven}</h1>} {/* Here we check if oddEven exists and then we display whatever we set in the OddEven function}
</div>
)
}
}
Here we set the state to what you want to render and then use that inside our render function.
Try This :
class App extends React.Component {
state = { val: '' };
handleChange = (e) => {
this.setState({ val: e.target.value });
}
OddEven(num) {
const number = parseInt(num);
if (Number.isInteger(number)) {
if (number % 2 == 0) {
return <strong>even</strong>;
} else {
return <i>odd</i>;
}
} else {
return <a>Please Enter A Number</a>;
}
}
render() {
return (
<div>
<input type='text' onChange={this.handleChange} />
{OddEven(this.state.val)}
</div>
);
}
render(){
return (
<div>
this.data.map(item=> {
<div aria-checked="true/false">{item}<div>
})
</div>
)
}
For the above code, I want to write an onClick handler that changes the value of aria-checked to true, depending on the item selected/clicked on. If one item is selected, it's aria-checked will be true and the rest false.
I know I need a checked component state with a boolean type but I'm not sure how to do the handler logic.
you can do by setAttribute, here:
constructor() {
super();
this.data = ["hello", "world"];
}
handleClick = (e) => {
const currentAriaChecked = (e.currentTarget.getAttribute("aria-checked") === 'true');
e.currentTarget.setAttribute("aria-checked", !currentAriaChecked);
};
render() {
return (
<div>
{
this.data
.map(item => (<div aria-checked="true" onClick={this.handleClick}>{item}</div>))
}
</div>
);
}
UPDATE
using typescript and react way
render() {
return (
<div>
{
this.data
.map(item => (<Check>{item}</Check>))
}
</div>
);
}
your component check
state = {
isChecked: false
}
handleClick = (e) => {
this.setState((prevState,props) => {
return {isChecked: !prevState.isChecked }
})
};
render() {
return (
<div aria-checked={this.state.isChecked} onClick={this.handleClick}>
{this.props.children} {this.state.isChecked.toString()}
</div>
);
}
see playground.
So in the example below i have validateResult which is set to the displayMessage. Depending on the user input it'd return a value, this is outside of the class component and i dont know how to test a function outside of the class with jest.
So i tried using mount from enzyme to mount the component then with instance to access the function but this gave me an error saying that this is not a function and im not sure how to test this.
test.js
const wrapper = mount (
<tempComponent />,
);
const instance = wrapper.instance();
it('expect result to be good', () => {
expect(instance.validateResult(true)).toBe("good");
});
tempComponent.js
const validateResult = (data) => {
if(data)
return "good";
else
return "bad";
};
class tempComponent extends Component {
constructor(props) {
super(props);
this.state = { inputdata: '' };
this.onSuccess = this.onSuccess.bind(this);
}
render() {
const { inputdata } = this.state;
const { onSubmit } = this.props;
const displayMessage = validateResult(inputdata);
return (
<div id="submit-form" className="row justify-content-center">
<div className="col-md-4">
<FormContainer onSubmit={() => onSubmit({ inputdata }, this.onSuccess)} >
<Input type="text" label="" onTextChange={(value) => this.setState({ ...this.state, inputdata: value })} text={inputdata} />
<SubmitButton value={'Submit'} disabled={displayMessage}/>
</FormContainer>
</div>
</div>
);
}
}