this.state.text.split() is undefined error when using onSubmitEditing - facebook

According to Facebook's official documentation:
onChangeText takes a function to be called every time the text changes
and
onSubmitEditing takes a function to be called when the text is submitted
I'm following the official Facebook tutorial on text input handling, the code:
export default class PizzaTranslator extends Component {
constructor(props) {
super(props);
this.state = {text: ''};
}
render() {
return (
<View style={{padding: 10}}>
<TextInput
style={{height: 40}}
placeholder="Type here to translate!"
onChangeText={(text) => this.setState({text})}
/>
<Text style={{padding: 10, fontSize: 42}}>
{this.state.text.split(' ').map((word) => word && '🍕').join(' ')}
</Text>
</View>
);
}
}
takes a sentence and change all of its words into 🍕 emojis, but if I change onChangeText to onSubmitEditing, I get an error saying this.state.text.split is not a function. (In 'this.state.text.split('')', 'this.state.text.split' is undefined) when I submit my text.

The documentation is correct on this point, both onChangeText and onSubmitEditing take a callback function to be executed. The essential difference is the argument supplied to the callback function. onChangeText gives the new value as a string and onSubmitEditing executes the callback function with an object as first argument. You can view the result using
<TextInput
onChangeText={(text) => {this.setState({text}); console.warn('text', text);}}
onSubmitEditing={(argument) => console.warn(Object.keys(argument))}
/>

Related

SolidJS: For in child component not rendering list

I have a parent component returning:
<List list={list()}>
{(item, index) => <div>{item}</div>}
</List>
where list is a created signal. List is a custom component I made returning:
<div>
<For each={list}>{children}</For>
</div>
but whenever list is updated, it isn't rendered. When I move the For code to the parent, it renders, so what is it about passing a signal's value to a child component that makes it not rerender on updates?
EDIT: demo
import { render } from "solid-js/web";
import { createSignal, For } from "solid-js";
function Counter() {
const [list, setList] = createSignal([]);
const increment = () => setList([...list(), 1]);
return (
<>
<button type="button" onClick={increment}>
add
</button>
<p>broken list</p>
<List list={list()} />
<p>other list</p>
<For each={list()}>
{(item) => <p>{item}</p>}
</For>
</>
);
}
function List({list}) {
return (
<For each={list}>
{(item) => <p>{item}</p>}
</For>
);
}
render(() => <Counter />, document.getElementById("app"));
EDIT 2: I meant to use <List list={list()} />, which also doesn't work, but I missed it earlier.
It does not work because destructuring props in Solid loses reactivity, that is, all the destructured props values do not update, ever.
Destructuring props is sometimes convenient and commonly used in other frameworks, but is not really recommended in Solid - the FAQ says:
By destructuring, you separate the value from the object, giving you the value at that point in time and losing reactivity.
You need to rewrite List component to use single props parameter and access props.list in the JSX:
function List(props) {
return (
<For each={props.list}>
{(item) => <p>{item}</p>}
</For>
);
}
Why destructuring does not work? In Solid, props is an object, created behind the scenes by Solid, with getters for intercepting access to each individual property, like props.something. It's needed to track JSX (expressions and fragments) and effects (created by createEffect()) so that they are reevaluated and updated when props.something changes. There's no way to track access to properties which are destructured (well there's plugin for that, but it's not in the core framework because it has some overhead).

How to handle state in Material UI Data Grid's components

I'm attempting to add search functionality to a data grid component. In order to achieve this, I'm adding an input element to the table using the components.header prop as follows (I've omitted irrelevant code):
const Table = () => {
const filterRows = (rows) => {
return rows;
};
const [searchTerm, setSearchTerm] = useState("");
const Header = () => (
<input
value={searchTerm}
onChange={(event) => setSearchTerm(event.target.value)}
/>
);
return (
<div style={{ height: 500 }}>
<DataGrid
rows={searchTerm ? filterRows(orders) : orders}
columns={orderColumns}
components={{
header: () => <Header />
}}
/>
</div>
);
};
The issue I'm having is that the input element loses focus each time a character is entered into the input in the header. Presumably, this is because it updates state, which triggers a re-render. This makes it impossible to share and access state of anything contained inside the Data Grid's components because it requires a React.FC argument and won't accept a ReactElement so the input is always re-rendered.
Am I missing something or is this actually not possible with Material UI's Data Grid? It seems like a pretty expected use-case to have something stateful in the header that we'd want to access like a controlled input component in order to use it as a kind of "Tool bar" as mentioned in the Material UI docs.
I've created a code sandbox to replicate the issue here: https://codesandbox.io/s/compassionate-keldysh-z995k?file=/src/App.js:246-726.
Cheers.

Delay on the capture of an image with React Native Camera / Expo Camera, set 'processing message'?

I have a huge delay in my app from when a user takes a photo to when android processes the image.
The issue of delay in Expo with android camera has been answered here: Delay on the capture of an image - React Native Camera / Expo Camera.
I am trying to see if, as well as see skipProcessing on takePictureAsync, is there a way to set a callback for on processing? I would like to let the user know something is happening, or they may try to take another photo (the camera stays open until the image has been processed, which is not ideal).
Here is my code:
export default class CameraComponent extends Component{
constructor(props) {
super(props)
}
render() {
<Camera
ref={(ref) => {
this.camera = ref;
}}
type={Camera.Constants.Type.back}
>
<TouchableOpacity
onPress={this.takePicture}
>
<View>
<FontAwesome
name="camera"
/>
</View>
</TouchableOpacity>
</Camera>;
}
takePicture = async () => {
const photo = await this.camera.takePictureAsync({
skipProcessing: true,
});
this.props.navigation.navigate("CameraConfirm", {
img_url: photo.img_url,
img_base64: photo.img_base64,
});
}
}
I can't see anything in the docs, is there maybe a way around in React Native? I tried setting state, but that still happens after takePictureAsync so has no effect.
I found one workaround which uses camera2API and onPictureSaved. The docs say there could be issues with camera2API, although I did not see anything weird going on (as yet).
The code now looks like this:
export default class CameraComponent extends Component{
constructor(props) {
super(props)
this.state = {
is_photo_taken: false,
};
}
render() {
<Camera
ref={(ref) => {
this.camera = ref;
}}
type={Camera.Constants.Type.back}
// add styling to show/hide camera:
style={{
display: this.state.is_photo_taken ? "none" : null,
}}
useCamera2Api={true} // add this line
>
<TouchableOpacity
onPress={this.takePicture}
>
<View>
<FontAwesome
name="camera"
/>
</View>
</TouchableOpacity>
</Camera>;
// add loading element with conditional show/hide:
<Text
style={{
display: !this.state.is_photo_taken ? "none" : null,
}}
>
Loading image...
</Text>
}
takePicture = async () => {
const photo = await this.camera.takePictureAsync({
onPictureSaved: this.setState({ is_photo_taken: true }), // add this line
// remove skipProcessing
});
this.props.navigation.navigate("CameraConfirm", {
img_url: photo.img_url,
img_base64: photo.img_base64,
});
}
}
Also, since onPictureSaved is now being used, it means that skipProcesssing can now be omitted, if not needed.
I used show/hide instead of ternaries or && around the entire block to avoid losing the camera element from the page. If the camera element were to be lost as soon as a photo was taken, then it could not continue and process the image.
I hope this helps someone.

building a basic search bar Material-UI

I want to build a really basic search bar with a search icon (similar to the one on Material-UI ) & invoke a function with the current value of the search field whenever the user hits enter or click on the search enter. I am new to Material-UI & I'm struggling to find my way through the different text fields elements.
I currently have this code
import Input from '#material-ui/core/Input';
class ...somecode
...somecode
constructor(props) {
super(props);
this.state = {
resources: [],
value: '',
};
}
handleChange(event) {
console.log(event.target.value);
this.setState({ value: event.target.value });
}
search(/* access value upons enter/ search icon click */) { <--------------------------
}
...some code
return (
<form id="search">
<Input type="text" value={value} onChange={(event) => { this.handleChange(event); }} placeholder="Search..." autoFocus fullWidth />
</form>
);
p.s: I had a really hard time fiddling around with all the APIs and options available in the input suite (I highly suggest an explanation of how they are related in the docs)

Identify which [SelectField] [DropDownMenu] fired onChange

I am programmatically rendering multiple SelectField and DropDownMenu components. I am trying to work with a single onChange handler functions, but I'm have not found a way to reference specific SelectField / DropDownMenu that triggered the event so I can update state accordingly.
The params passed for the onChange event seem not to contain any helpful information to identify the firing components. Any ideas?
Here's an example of how this can be done
https://jsfiddle.net/davidebarros/k9ng7bk9/
This is assuming you are familiar with the es6 arrow function syntax.
state = {
dropDown1: 1,
dropDown2: 4,
selectfield1: null,
selectfield2: null
}
onChange = (type) => (event, index, value) => {
this.setState({
[type]: value
})
//In your render method
<SelectField
floatingLabelText="Select Field 1"
value={this.state.selectfield1}
onChange={this.onChange("selectfield1")}>
<MenuItem value={1} primaryText="Select 1, value 1" />
<MenuItem value={2} primaryText="Select 1, value 2" />
</SelectField>